pyppin.base.registered_class¶
Make it easy to look up subclasses of an abstract class by name.
Classes
|
A metaclass to make classes findable through a registry. |
- class pyppin.base.registered_class.RegisteredClass(name: str, bases: Tuple[Type], namespace: Dict[str, Any], register: bool = True, registration_name: Optional[str] = None)[source]¶
Bases:
type
A metaclass to make classes findable through a registry.
RegisteredClass is a metaclass that lets you define classes whose subclasses you can look up by name. This is useful if (for example) you want to define an abstract class in a library, have users of the library define their own implementations of that class, and pick which implementation you want to use at runtime based on a parameter. For example:
class AbstractWorker(metaclass=RegisteredClass): ... define some stuff ... @classmethod def make(cls, worker: str, other_arguments) -> "AbstractWorker": return RegisteredClass.get(AbstractWorker, worker)(other_arguments) # In another file class RealWorker(AbstractWorker): ... just a normal subclass ...
You access this registration using two static methods:
RegisteredClass.get(superclass, name)
returns a named subclass of the superclassRegisteredClass.subclasses(superclass)
returns all registered subclasses of that class.
Or via class methods:
AbstractWorker.get_subclass(name) # type: ignore
AbstractWorker.subclasses() # type: ignore
You can also define “intermediate” classes which don’t themselves appear in the registry. For example:
class RemoteWorker(AbstractWorker, register=False): # type: ignore ... some partial implementation of AbstractWorker ... class RealRemoteWorker(RemoteWorker): ... a concrete worker ...
Then
RegisteredClass.subclasses(AbstractWorker)
will return RealWorker and RealRemoteWorker (but not RemoteWorker), andRegisteredClass.subclasses(RemoteWorker)
will return RealRemoteWorker.Every subclass must be registered with a unique name, which by default is just the name of the class. You can override this with
registration_name="Foo"
.MYPY WARNING: There are some bugs in the way mypy handles dynamic type declarations. As a result, if you use any of the class methods (rather than
RegistrationClass.*
) or if you pass any arguments like register or registration_name, you have to mark the line as# type: ignore
. Sorry.- static get(superclass: RegisteredClass, name: str) RegisteredClass [source]¶
Get a named subclass of superclass.
- Parameters
superclass – A class whose metaclass is RegisteredClass.
name – The name under which a subclass was registered – usually the name of the class, unless you’ve set registration_name in its class declaration.
- static subclasses(superclass: RegisteredClass) Dict[str, RegisteredClass] [source]¶
Return all the subclasses of a given registered class.