#-----------------------------------------------------------------------------# Copyright (c) 2012 - 2022, Anaconda, Inc., and Bokeh Contributors.# All rights reserved.## The full license is in the file LICENSE.txt, distributed with this software.#-----------------------------------------------------------------------------""" Provide the Instance property.The Instance property is used to construct object graphs of Bokeh models,where one Bokeh model refers to another."""#-----------------------------------------------------------------------------# Boilerplate#-----------------------------------------------------------------------------from__future__importannotationsimportlogging# isort:skiplog=logging.getLogger(__name__)#-----------------------------------------------------------------------------# Imports#-----------------------------------------------------------------------------# Standard library importsfromimportlibimportimport_modulefromtypingimport(TYPE_CHECKING,Any,Dict,Type,TypeVar,)# Bokeh importsfrom._sphinximportmodel_link,property_link,register_type_linkfrom.basesimportDeserializationError,Init,Propertyfrom.singletonsimportUndefinedifTYPE_CHECKING:from..has_propsimportHasPropsfrom..typesimportJSON#-----------------------------------------------------------------------------# Globals and constants#-----------------------------------------------------------------------------__all__=('Instance',)T=TypeVar("T",bound="HasProps")#-----------------------------------------------------------------------------# General API#-----------------------------------------------------------------------------
[docs]classInstance(Property[T]):""" Accept values that are instances of |HasProps|. Args: readonly (bool, optional) : Whether attributes created from this property are read-only. (default: False) """_instance_type:Type[T]|strdef__init__(self,instance_type:Type[T]|str,default:Init[T]=Undefined,help:str|None=None,readonly:bool=False,serialized:bool|None=None):ifnotisinstance(instance_type,(type,str)):raiseValueError(f"expected a type or string, got {instance_type}")from..has_propsimportHasPropsifisinstance(instance_type,type)andnotissubclass(instance_type,HasProps):raiseValueError(f"expected a subclass of HasProps, got {instance_type}")self._instance_type=instance_typesuper().__init__(default=default,help=help,readonly=readonly,serialized=serialized)def__str__(self)->str:class_name=self.__class__.__name__instance_type=self.instance_type.__name__returnf"{class_name}({instance_type})"@propertydefhas_ref(self)->bool:returnTrue@propertydefinstance_type(self)->Type[HasProps]:ifisinstance(self._instance_type,str):module,name=self._instance_type.rsplit(".",1)self._instance_type=getattr(import_module(module,"bokeh"),name)returnself._instance_typedeffrom_json(self,json:JSON,*,models:Dict[str,HasProps]|None=None)->T:ifisinstance(json,dict):from...modelimportModelifissubclass(self.instance_type,Model):ifmodelsisNone:raiseDeserializationError(f"{self} can't deserialize without models")else:model=models.get(json["id"])ifmodelisnotNone:returnmodelelse:raiseDeserializationError(f"{self} failed to deserialize reference to {json}")else:attrs={}forname,valueinjson.items():prop_descriptor=self.instance_type.lookup(name).propertyattrs[name]=prop_descriptor.from_json(value,models=models)# XXX: this doesn't work when Instance(Superclass) := Subclass()# Serialization dict must carry type information to resolve this.returnself.instance_type(**attrs)else:raiseDeserializationError(f"{self} expected a dict, got {json}")defvalidate(self,value:Any,detail:bool=True)->None:super().validate(value,detail)ifisinstance(value,self.instance_type):returninstance_type=self.instance_type.__name__value_type=type(value).__name__msg=""ifnotdetailelsef"expected an instance of type {instance_type}, got {value} of type {value_type}"raiseValueError(msg)def_may_have_unstable_default(self):# because the instance value is mutablereturnTrue
#-----------------------------------------------------------------------------# Dev API#-----------------------------------------------------------------------------#-----------------------------------------------------------------------------# Private API#-----------------------------------------------------------------------------#-----------------------------------------------------------------------------# Code#-----------------------------------------------------------------------------@register_type_link(Instance)def_sphinx_type_link(obj):fullname=f"{obj.instance_type.__module__}.{obj.instance_type.__name__}"returnf"{property_link(obj)}({model_link(fullname)})"