#-----------------------------------------------------------------------------# Copyright (c) Anaconda, Inc., and Bokeh Contributors.# All rights reserved.## The full license is in the file LICENSE.txt, distributed with this software.#-----------------------------------------------------------------------------""" Various ways for constraining values of other properties."""#-----------------------------------------------------------------------------# Boilerplate#-----------------------------------------------------------------------------from__future__importannotationsimportlogging# isort:skiplog=logging.getLogger(__name__)#-----------------------------------------------------------------------------# Imports#-----------------------------------------------------------------------------# Standard library importsfromtypingimportAny,TypeVar# Bokeh importsfrom._sphinximportproperty_link,register_type_link,type_linkfrom.basesimport(Init,Property,SingleParameterizedProperty,TypeOrInst,)from.singletonsimportIntrinsic#-----------------------------------------------------------------------------# Globals and constants#-----------------------------------------------------------------------------__all__=("TypeOfAttr",)T=TypeVar("T")#-----------------------------------------------------------------------------# General API#-----------------------------------------------------------------------------
[docs]classTypeOfAttr(SingleParameterizedProperty[T]):""" Allows to check if an attribute of an object satisfies the given type or a collection of types. """def__init__(self,type_param:TypeOrInst[Property[T]],name:str,type:TypeOrInst[Property[Any]],*,default:Init[T]=Intrinsic,help:str|None=None,)->None:super().__init__(type_param,default=default,help=help)self._query_name=nameself._query_type=self._validate_type_param(type)def__call__(self,*,default:Init[T]=Intrinsic,help:str|None=None)->TypeOfAttr[T]:""" Clone this property and allow to override ``default`` and ``help``. """default=self._defaultifdefaultisIntrinsicelsedefaulthelp=self._helpifhelpisNoneelsehelpprop=self.__class__(self.type_param,self._query_name,self._query_type,default=default,help=help)prop.alternatives=list(self.alternatives)prop.assertions=list(self.assertions)returnpropdef__str__(self)->str:class_name=self.__class__.__name__returnf"{class_name}({self.type_param}, {self._query_name!r}, {self._query_type})"defvalidate(self,value:Any,detail:bool=True)->None:super().validate(value,detail)name=self._query_nametype=self._query_typetry:attr=getattr(value,name)exceptAttributeError:raiseValueError(f"expected {value!r} to have an attribute '{name}'"ifdetailelse"")iftype.is_valid(attr):returnraiseValueError(f"expected {value!r} to have an attribute {name!r} of type {type}"ifdetailelse"")
#-----------------------------------------------------------------------------# Dev API#-----------------------------------------------------------------------------#-----------------------------------------------------------------------------# Private API#-----------------------------------------------------------------------------#-----------------------------------------------------------------------------# Code#-----------------------------------------------------------------------------@register_type_link(TypeOfAttr)def_sphinx_type_link(obj:SingleParameterizedProperty[Any])->str:returnf"{property_link(obj)}({type_link(obj.type_param)})"