#-----------------------------------------------------------------------------# Copyright (c) 2012 - 2023, Anaconda, Inc., and Bokeh Contributors.# All rights reserved.## The full license is in the file LICENSE.txt, distributed with this software.#-----------------------------------------------------------------------------""" Provide the Either property.The Either property is used to construct properties that an accept any ofmultiple possible types."""#-----------------------------------------------------------------------------# Boilerplate#-----------------------------------------------------------------------------from__future__importannotationsimportlogging# isort:skiplog=logging.getLogger(__name__)#-----------------------------------------------------------------------------# Imports#-----------------------------------------------------------------------------# Standard library importsfromtypingimportAny,TypeVar# Bokeh importsfrom...util.stringsimportnice_joinfrom._sphinximportproperty_link,register_type_link,type_linkfrom.basesimport(Init,ParameterizedProperty,Property,TypeOrInst,)from.singletonsimportIntrinsic#-----------------------------------------------------------------------------# Globals and constants#-----------------------------------------------------------------------------__all__=('Either',)T=TypeVar("T")#-----------------------------------------------------------------------------# General API#-----------------------------------------------------------------------------
[docs]classEither(ParameterizedProperty[Any]):""" Accept values according to a sequence of other property types. Example: .. code-block:: python >>> class EitherModel(HasProps): ... prop = Either(Bool, Int, Auto) ... >>> m = EitherModel() >>> m.prop = True >>> m.prop = 10 >>> m.prop = "auto" >>> m.prop = 10.3 # ValueError !! >>> m.prop = "foo" # ValueError !! """def__init__(self,type_param0:TypeOrInst[Property[Any]],*type_params:TypeOrInst[Property[Any]],default:Init[T]=Intrinsic,help:str|None=None)->None:super().__init__(type_param0,*type_params,default=default,help=help)fortpinself.type_params:self.alternatives.extend(tp.alternatives)deftransform(self,value:Any)->Any:forparaminself.type_params:try:returnparam.transform(value)exceptValueError:passraiseValueError(f"Could not transform {value!r}")defvalidate(self,value:Any,detail:bool=True)->None:super().validate(value,detail)ifany(param.is_valid(value)forparaminself.type_params):returnmsg=""ifnotdetailelsef"expected an element of either {nice_join([str(param)forparaminself.type_params])}, got {value!r}"raiseValueError(msg)defwrap(self,value):fortpinself.type_params:value=tp.wrap(value)returnvaluedefreplace(self,old:type[Property[Any]],new:Property[Any])->Property[Any]:ifself.__class__==old:returnnewelse:params=[type_param.replace(old,new)fortype_paraminself.type_params]returnEither(*params)
#-----------------------------------------------------------------------------# Dev API#-----------------------------------------------------------------------------#-----------------------------------------------------------------------------# Private API#-----------------------------------------------------------------------------#-----------------------------------------------------------------------------# Code#-----------------------------------------------------------------------------@register_type_link(Either)def_sphinx_type_link(obj:Either[Any]):subtypes=", ".join(type_link(x)forxinobj.type_params)returnf"{property_link(obj)}({subtypes})"