Retrieve the unique dispatch key for a class type or instance.
This key is defined at the __dispatch_key__ attribute. If it is a callable, it
will be resolved.
If allow_missing is False, an exception will be raised if the attribute is not
defined or the key is null. If True, None will be returned in these cases.
defget_dispatch_key(cls_or_instance:Any,allow_missing:bool=False)->Optional[str]:""" Retrieve the unique dispatch key for a class type or instance. This key is defined at the `__dispatch_key__` attribute. If it is a callable, it will be resolved. If `allow_missing` is `False`, an exception will be raised if the attribute is not defined or the key is null. If `True`, `None` will be returned in these cases. """dispatch_key=getattr(cls_or_instance,"__dispatch_key__",None)type_name=(cls_or_instance.__name__ifisinstance(cls_or_instance,type)elsetype(cls_or_instance).__name__)ifdispatch_keyisNone:ifallow_missing:returnNoneraiseValueError(f"Type {type_name!r} does not define a value for ""'__dispatch_key__' which is required for registry lookup.")ifcallable(dispatch_key):dispatch_key=dispatch_key()ifallow_missinganddispatch_keyisNone:returnNoneifnotisinstance(dispatch_key,str):raiseTypeError(f"Type {type_name!r} has a '__dispatch_key__' of type "f"{type(dispatch_key).__name__} but a type of 'str' is required.")returndispatch_key
Get the first matching registry for a class or any of its base classes.
If not found, None is returned.
Source code in src/prefect/utilities/dispatch.py
33343536373839404142434445
defget_registry_for_type(cls:T)->Optional[Dict[str,T]]:""" Get the first matching registry for a class or any of its base classes. If not found, `None` is returned. """returnnext(filter(lambdaregistry:registryisnotNone,(_TYPE_REGISTRIES.get(cls)forclsincls.mro()),),None,)
deflookup_type(cls:T,dispatch_key:str)->T:""" Look up a dispatch key in the type registry for the given class. """# Get the first matching registry for the class or one of its basesregistry=get_registry_for_type(cls)# Look up this type in the registrysubcls=registry.get(dispatch_key)ifsubclsisNone:raiseKeyError(f"No class found for dispatch key {dispatch_key!r} in registry for type "f"{cls.__name__!r}.")returnsubcls
defregister_base_type(cls:T)->T:""" Register a base type allowing child types to be registered for dispatch with `register_type`. The base class may or may not define a `__dispatch_key__` to allow lookups of the base type. """registry=_TYPE_REGISTRIES.setdefault(cls,{})base_key=get_dispatch_key(cls,allow_missing=True)ifbase_keyisnotNone:registry[base_key]=cls# Add automatic subtype registrationcls.__init_subclass_original__=getattr(cls,"__init_subclass__")cls.__init_subclass__=_register_subclass_of_base_typereturncls
defregister_type(cls:T)->T:""" Register a type for lookup with dispatch. The type or one of its parents must define a unique `__dispatch_key__`. One of the classes base types must be registered using `register_base_type`. """# Lookup the registry for this typeregistry=get_registry_for_type(cls)# Check if a base type is registeredifregistryisNone:# Include a description of registered base typesknown=", ".join(repr(base.__name__)forbasein_TYPE_REGISTRIES)known_message=(f" Did you mean to inherit from one of the following known types: {known}."ifknownelse"")# And a list of all base types for the type they tried to registerbases=", ".join(repr(base.__name__)forbaseincls.mro()ifbasenotin(object,cls))raiseValueError(f"No registry found for type {cls.__name__!r} with bases {bases}."+known_message)key=get_dispatch_key(cls)existing_value=registry.get(key)ifexisting_valueisnotNoneandid(existing_value)!=id(cls):# Get line numbers for debuggingfile=inspect.getsourcefile(cls)line_number=inspect.getsourcelines(cls)[1]existing_file=inspect.getsourcefile(existing_value)existing_line_number=inspect.getsourcelines(existing_value)[1]warnings.warn(f"Type {cls.__name__!r} at {file}:{line_number} has key {key!r} that "f"matches existing registered type {existing_value.__name__!r} from "f"{existing_file}:{existing_line_number}. The existing type will be ""overridden.")# Add to the registryregistry[key]=clsreturncls