summaryrefslogtreecommitdiff
path: root/buildscripts/resmokelib/utils/registry.py
blob: 0a18c556e941f4735986aa3b532335b5e3f3d76a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
"""
Utility for having class declarations automatically cause a reference to
the class to be stored along with its name.

This pattern enables the associated class to be looked up later by using
its name.
"""

from __future__ import absolute_import

# Specifying 'LEAVE_UNREGISTERED' as the "REGISTERED_NAME" attribute will cause the class to be
# omitted from the registry. This is particularly useful for base classes that define an interface
# or common functionality, and aren't intended to be constructed explicitly.
LEAVE_UNREGISTERED = object()


def make_registry_metaclass(registry_store):
    """
    Returns a new Registry metaclass.
    """

    if not isinstance(registry_store, dict):
        raise TypeError("'registry_store' argument must be a dict")

    class Registry(type):
        """
        A metaclass that stores a reference to all registered classes.
        """

        def __new__(meta, class_name, base_classes, class_dict):
            """
            Creates and returns a new instance of Registry, which is a
            class named 'class_name' derived from 'base_classes' that
            defines 'class_dict' as additional attributes.

            The returned class is added to 'registry_store' using
            class_dict["REGISTERED_NAME"] as the name, or 'class_name'
            if the "REGISTERED_NAME" attribute isn't defined. If the
            sentinel value 'LEAVE_UNREGISTERED' is specified as the
            name, then the returned class isn't added to
            'registry_store'.

            The returned class will have the "REGISTERED_NAME" attribute
            defined either as its associated key in 'registry_store' or
            the 'LEAVE_UNREGISTERED' sentinel value.
            """

            registered_name = class_dict.setdefault("REGISTERED_NAME", class_name)
            cls = type.__new__(meta, class_name, base_classes, class_dict)

            if registered_name is not LEAVE_UNREGISTERED:
                if registered_name in registry_store:
                    raise ValueError("The name %s is already registered; a different value for the"
                                     " 'REGISTERED_NAME' attribute must be chosen" %
                                     (registered_name))
                registry_store[registered_name] = cls

            return cls

    return Registry