import os from typing import Callable, Optional, Sequence, TypeVar from rest_framework.exceptions import ValidationError def cast_bool_from_str(value): if isinstance(value, str): if value.lower() in ['true', 'yes', 'on', '1']: value = True elif value.lower() in ['false', 'no', 'not', 'off', '0']: value = False else: raise ValueError(f'Incorrect bool value "{value}". ' f'It should be one of [1, 0, true, false, yes, no]') return value def bool_from_request(params, key, default): """Get boolean value from request GET, POST, etc :param params: dict POST, GET, etc :param key: key to find :param default: default value :return: boolean """ value = params.get(key, default) try: if isinstance(value, str): value = cast_bool_from_str(value) return bool(int(value)) except Exception as e: raise ValidationError({key: str(e)}) def int_from_request(params, key, default): """Get integer from request GET, POST, etc :param params: dict POST, GET, etc :param key: key to find :param default: default value :return: int """ value = params.get(key, default) # str if isinstance(value, str): try: return int(value) except ValueError: raise ValidationError({key: f'Incorrect value in key "{key}" = "{value}". It should be digit string.'}) except Exception as e: raise ValidationError({key: str(e)}) # int elif isinstance(value, int): return value # other else: raise ValidationError( {key: f'Incorrect value type in key "{key}" = "{value}". ' f'It should be digit string or integer.'} ) def float_from_request(params, key, default): """Get float from request GET, POST, etc :param params: dict POST, GET, etc :param key: key to find :param default: default value :return: float """ value = params.get(key, default) # str if isinstance(value, str): try: return float(value) except ValueError: raise ValidationError({key: f'Incorrect value in key "{key}" = "{value}". It should be digit string.'}) # float elif isinstance(value, float) or isinstance(value, int): return float(value) # other else: raise ValidationError( {key: f'Incorrect value type in key "{key}" = "{value}". ' f'It should be digit string or float.'} ) def list_of_strings_from_request(params, key, default): """Get list of strings from request GET, POST, etc :param params: dict POST, GET, etc :param key: key to find :param default: default value :return: float """ value = params.get(key, default) if value is None: return splitters = (',', ';', '|') # str if isinstance(value, str): for splitter in splitters: if splitter in value: return value.split(splitter) return [value] else: raise ValidationError( {key: f'Incorrect value type in key "{key}" = "{value}". ' f'It should be digit string or float.'} ) def get_env(name, default=None, is_bool=False): for env_key in ['LABEL_STUDIO_' + name, 'HEARTEX_' + name, name]: value = os.environ.get(env_key) if value is not None: if is_bool: return bool_from_request(os.environ, env_key, default) else: return value return default def has_env(name: str) -> bool: """Return True if any supported environment variable name is set for ``name``.""" return any((prefix + name) in os.environ for prefix in ('LABEL_STUDIO_', 'HEARTEX_', '')) def get_bool_env(key, default): return get_env(key, default, is_bool=True) T = TypeVar('T') def get_env_list( key: str, default: Optional[Sequence[T]] = None, value_transform: Callable[[str], T] = str ) -> Sequence[T]: """ "foo,bar,baz" in env variable => ["foo", "bar", "baz"] in python. Use value_transform to convert the strings to any other type. """ value = get_env(key) if not value: if default is None: return [] return default return [value_transform(el) for el in value.split(',')] def get_env_list_int(key, default=None) -> Sequence[int]: return get_env_list(key, default=default, value_transform=int) def get_all_env_with_prefix(prefix=None, is_bool=True, default_value=None): out = {} for key in os.environ.keys(): if not key.startswith(prefix): continue if is_bool: out[key] = bool_from_request(os.environ, key, default_value) else: out[key] = os.environ[key] return out