Load all inheritance data from the OrientDB schema. Used as part of __init__.

def _set_up_inheritance_and_subclass_sets(self, schema_data):
        """Load all inheritance data from the OrientDB schema. Used as part of __init__."""
        # For each class name, construct its inheritance set:
        # itself + the set of class names from which it inherits.
        for class_definition in schema_data:
            class_name = class_definition['name']
            immediate_superclass_names = get_superclasses_from_class_definition(
                class_definition)

            inheritance_set = set(immediate_superclass_names)
            inheritance_set.add(class_name)

            # Since the input data must be in topological order, the superclasses of
            # the current class should have already been processed.
            # A KeyError on the following line would mean that the input
            # was not topologically sorted.
            inheritance_set.update(chain.from_iterable(
                self._inheritance_sets[superclass_name]
                for superclass_name in immediate_superclass_names
            ))

            # Freeze the inheritance set so it can't ever be modified again.
            self._inheritance_sets[class_name] = frozenset(inheritance_set)

        # For each class name, construct its subclass set:
        # itself + the set of class names that inherit from it.
        for subclass_name, superclass_names in six.iteritems(self._inheritance_sets):
            for superclass_name in superclass_names:
                self._subclass_sets.setdefault(
                    superclass_name, set()).add(subclass_name)

        # Freeze all subclass sets so they can never be modified again,
        # making a list of all keys before modifying any of their values.
        # It's bad practice to mutate a dict while iterating over it.
        for class_name in list(six.iterkeys(self._subclass_sets)):
            self._subclass_sets[class_name] = frozenset(self._subclass_sets[class_name])