pyppin.base.registered_class

[View Source]

Make it easy to look up subclasses of an abstract class by name.

Classes

RegisteredClass(name, bases, namespace[, ...])

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 superclass

  • RegisteredClass.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), and RegisteredClass.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.