def _get_annotation_heading(self, handler, route, heading=None):
        """Returns the heading text for an annotation.

        Attempts to get the name of the heading from the handler attribute
        `schematic_title` first.

        If `schematic_title` it is not present, it attempts to generate
        the title from the class path.
        This path: advertiser_api.handlers.foo_bar.FooListHandler
        would translate to 'Foo Bar'

        If the file name with the resource is generically named handlers.py
        or it doesn't have a full path then we attempt to get the resource
        name from the class name.
        So FooListHandler and FooHandler would translate to 'Foo'.
        If the handler class name starts with 'Internal', then that will
        be appended to the heading.
        So InternalFooListHandler would translate to 'Foo (Internal)'

        :param mixed handler: The handler class.  Will be a flask resource class
        :param str route: The route to the handler.
        :returns: The text for the heading as a string.
        """
        if hasattr(handler, '_doctor_heading'):
            return handler._doctor_heading

        heading = ''
        handler_path = str(handler)
        try:
            handler_file_name = handler_path.split('.')[-2]
        except IndexError:
            # In the event there is no path and we just have the class name,
            # get heading from the class name by setting us up to enter the
            # first if statement.
            handler_file_name = 'handler'

        # Get heading from class name
        if handler_file_name.startswith('handler'):
            class_name = handler_path.split('.')[-1]
            internal = False
            for word in CAMEL_CASE_RE.findall(class_name):
                if word == 'Internal':
                    internal = True
                    continue
                elif word.startswith(('List', 'Handler', 'Resource')):
                    # We've hit the end of the class name that contains
                    # words we are interested in.
                    break
                heading += '%s ' % (word,)
            if internal:
                heading = heading.strip()
                heading += ' (Internal)'
        # Get heading from handler file name
        else:
            heading = ' '.join(handler_file_name.split('_')).title()
            if 'internal' in route:
                heading += ' (Internal)'
        return heading.strip()
Returns the heading text for an annotation.

        Attempts to get the name of the heading from the handler attribute
        `schematic_title` first.

        If `schematic_title` it is not present, it attempts to generate
        the title from the class path.
        This path: advertiser_api.handlers.foo_bar.FooListHandler
        would translate to 'Foo Bar'

        If the file name with the resource is generically named handlers.py
        or it doesn't have a full path then we attempt to get the resource
        name from the class name.
        So FooListHandler and FooHandler would translate to 'Foo'.
        If the handler class name starts with 'Internal', then that will
        be appended to the heading.
        So InternalFooListHandler would translate to 'Foo (Internal)'

        :param mixed handler: The handler class.  Will be a flask resource class
        :param str route: The route to the handler.
        :returns: The text for the heading as a string.