[docs]defxor_args(*arg_groups:Tuple[str,...])->Callable:"""Validate specified keyword args are mutually exclusive." Args: *arg_groups (Tuple[str, ...]): Groups of mutually exclusive keyword args. Returns: Callable: Decorator that validates the specified keyword args are mutually exclusive Raises: ValueError: If more than one arg in a group is defined. """defdecorator(func:Callable)->Callable:@functools.wraps(func)defwrapper(*args:Any,**kwargs:Any)->Any:"""Validate exactly one arg in each group is not None."""counts=[sum(1forarginarg_groupifkwargs.get(arg)isnotNone)forarg_groupinarg_groups]invalid_groups=[ifori,countinenumerate(counts)ifcount!=1]ifinvalid_groups:invalid_group_names=[", ".join(arg_groups[i])foriininvalid_groups]raiseValueError("Exactly one argument in each of the following"" groups must be defined:"f" {', '.join(invalid_group_names)}")returnfunc(*args,**kwargs)returnwrapperreturndecorator
[docs]defraise_for_status_with_text(response:Response)->None:"""Raise an error with the response text. Args: response (Response): The response to check for errors. Raises: ValueError: If the response has an error status code. """try:response.raise_for_status()exceptHTTPErrorase:raiseValueError(response.text)frome
[docs]@contextlib.contextmanagerdefmock_now(dt_value):# type: ignore"""Context manager for mocking out datetime.now() in unit tests. Args: dt_value: The datetime value to use for datetime.now(). Yields: datetime.datetime: The mocked datetime class. Example: with mock_now(datetime.datetime(2011, 2, 3, 10, 11)): assert datetime.datetime.now() == datetime.datetime(2011, 2, 3, 10, 11) """classMockDateTime(datetime.datetime):"""Mock datetime.datetime.now() with a fixed datetime."""@classmethoddefnow(cls):# type: ignore# Create a copy of dt_value.returndatetime.datetime(dt_value.year,dt_value.month,dt_value.day,dt_value.hour,dt_value.minute,dt_value.second,dt_value.microsecond,dt_value.tzinfo,)real_datetime=datetime.datetimedatetime.datetime=MockDateTimetry:yielddatetime.datetimefinally:datetime.datetime=real_datetime
[docs]defguard_import(module_name:str,*,pip_name:Optional[str]=None,package:Optional[str]=None)->Any:"""Dynamically import a module and raise an exception if the module is not installed. Args: module_name (str): The name of the module to import. pip_name (str, optional): The name of the module to install with pip. Defaults to None. package (str, optional): The package to import the module from. Defaults to None. Returns: Any: The imported module. Raises: ImportError: If the module is not installed. """try:module=importlib.import_module(module_name,package)except(ImportError,ModuleNotFoundError)ase:pip_name=pip_nameormodule_name.split(".")[0].replace("_","-")raiseImportError(f"Could not import {module_name} python package. "f"Please install it with `pip install {pip_name}`.")fromereturnmodule
[docs]defcheck_package_version(package:str,lt_version:Optional[str]=None,lte_version:Optional[str]=None,gt_version:Optional[str]=None,gte_version:Optional[str]=None,)->None:"""Check the version of a package. Args: package (str): The name of the package. lt_version (str, optional): The version must be less than this. Defaults to None. lte_version (str, optional): The version must be less than or equal to this. Defaults to None. gt_version (str, optional): The version must be greater than this. Defaults to None. gte_version (str, optional): The version must be greater than or equal to this. Defaults to None. Raises: ValueError: If the package version does not meet the requirements. """imported_version=parse(version(package))iflt_versionisnotNoneandimported_version>=parse(lt_version):raiseValueError(f"Expected {package} version to be < {lt_version}. Received "f"{imported_version}.")iflte_versionisnotNoneandimported_version>parse(lte_version):raiseValueError(f"Expected {package} version to be <= {lte_version}. Received "f"{imported_version}.")ifgt_versionisnotNoneandimported_version<=parse(gt_version):raiseValueError(f"Expected {package} version to be > {gt_version}. Received "f"{imported_version}.")ifgte_versionisnotNoneandimported_version<parse(gte_version):raiseValueError(f"Expected {package} version to be >= {gte_version}. Received "f"{imported_version}.")
[docs]defget_pydantic_field_names(pydantic_cls:Any)->Set[str]:"""Get field names, including aliases, for a pydantic class. Args: pydantic_cls: Pydantic class. Returns: Set[str]: Field names. """all_required_field_names=set()ifis_pydantic_v1_subclass(pydantic_cls):forfieldinpydantic_cls.__fields__.values():all_required_field_names.add(field.name)iffield.has_alias:all_required_field_names.add(field.alias)else:# Assuming pydantic 2 for nowforname,fieldinpydantic_cls.model_fields.items():all_required_field_names.add(name)iffield.alias:all_required_field_names.add(field.alias)returnall_required_field_names
[docs]defbuild_extra_kwargs(extra_kwargs:Dict[str,Any],values:Dict[str,Any],all_required_field_names:Set[str],)->Dict[str,Any]:"""Build extra kwargs from values and extra_kwargs. Args: extra_kwargs: Extra kwargs passed in by user. values: Values passed in by user. all_required_field_names: All required field names for the pydantic class. Returns: Dict[str, Any]: Extra kwargs. Raises: ValueError: If a field is specified in both values and extra_kwargs. ValueError: If a field is specified in model_kwargs. """forfield_nameinlist(values):iffield_nameinextra_kwargs:raiseValueError(f"Found {field_name} supplied twice.")iffield_namenotinall_required_field_names:warnings.warn(f"""WARNING! {field_name} is not default parameter.{field_name} was transferred to model_kwargs. Please confirm that {field_name} is what you intended.""",stacklevel=7,)extra_kwargs[field_name]=values.pop(field_name)invalid_model_kwargs=all_required_field_names.intersection(extra_kwargs.keys())ifinvalid_model_kwargs:raiseValueError(f"Parameters {invalid_model_kwargs} should be specified explicitly. "f"Instead they were passed in as part of `model_kwargs` parameter.")returnextra_kwargs
[docs]defconvert_to_secret_str(value:Union[SecretStr,str])->SecretStr:"""Convert a string to a SecretStr if needed. Args: value (Union[SecretStr, str]): The value to convert. Returns: SecretStr: The SecretStr value. """ifisinstance(value,SecretStr):returnvaluereturnSecretStr(value)
class_NoDefaultType:"""Type to indicate no default value is provided."""pass_NoDefault=_NoDefaultType()@overloaddeffrom_env(key:str,/)->Callable[[],str]:...@overloaddeffrom_env(key:str,/,*,default:str)->Callable[[],str]:...@overloaddeffrom_env(key:Sequence[str],/,*,default:str)->Callable[[],str]:...@overloaddeffrom_env(key:str,/,*,error_message:str)->Callable[[],str]:...@overloaddeffrom_env(key:Union[str,Sequence[str]],/,*,default:str,error_message:Optional[str])->Callable[[],str]:...@overloaddeffrom_env(key:str,/,*,default:None,error_message:Optional[str])->Callable[[],Optional[str]]:...@overloaddeffrom_env(key:Union[str,Sequence[str]],/,*,default:None)->Callable[[],Optional[str]]:...
[docs]deffrom_env(key:Union[str,Sequence[str]],/,*,default:Union[str,_NoDefaultType,None]=_NoDefault,error_message:Optional[str]=None,)->Union[Callable[[],str],Callable[[],Optional[str]]]:"""Create a factory method that gets a value from an environment variable. Args: key: The environment variable to look up. If a list of keys is provided, the first key found in the environment will be used. If no key is found, the default value will be used if set, otherwise an error will be raised. default: The default value to return if the environment variable is not set. error_message: the error message which will be raised if the key is not found and no default value is provided. This will be raised as a ValueError. """defget_from_env_fn()->Optional[str]:"""Get a value from an environment variable."""ifisinstance(key,(list,tuple)):forkinkey:ifkinos.environ:returnos.environ[k]ifisinstance(key,str):ifkeyinos.environ:returnos.environ[key]ifisinstance(default,(str,type(None))):returndefaultelse:iferror_message:raiseValueError(error_message)else:raiseValueError(f"Did not find {key}, please add an environment variable"f" `{key}` which contains it, or pass"f" `{key}` as a named parameter.")returnget_from_env_fn
[docs]defsecret_from_env(key:Union[str,Sequence[str]],/,*,default:Union[str,_NoDefaultType,None]=_NoDefault,error_message:Optional[str]=None,)->Union[Callable[[],Optional[SecretStr]],Callable[[],SecretStr]]:"""Secret from env. Args: key: The environment variable to look up. default: The default value to return if the environment variable is not set. error_message: the error message which will be raised if the key is not found and no default value is provided. This will be raised as a ValueError. Returns: factory method that will look up the secret from the environment. """defget_secret_from_env()->Optional[SecretStr]:"""Get a value from an environment variable."""ifisinstance(key,(list,tuple)):forkinkey:ifkinos.environ:returnSecretStr(os.environ[k])ifisinstance(key,str):ifkeyinos.environ:returnSecretStr(os.environ[key])ifisinstance(default,str):returnSecretStr(default)elifisinstance(default,type(None)):returnNoneelse:iferror_message:raiseValueError(error_message)else:raiseValueError(f"Did not find {key}, please add an environment variable"f" `{key}` which contains it, or pass"f" `{key}` as a named parameter.")returnget_secret_from_env