Generate a graphviz dot graph from the classes that were passed in
        to __init__.

        *name* is the name of the graph.

        *urls* is a dictionary mapping class names to HTTP URLs.

        *graph_attrs*, *node_attrs*, *edge_attrs* are dictionaries containing
        key/value pairs to pass on as graphviz properties.

def generate_dot(self, name, urls={}, env=None,
                     graph_attrs={}, node_attrs={}, edge_attrs={}):
        # type: (unicode, Dict, BuildEnvironment, Dict, Dict, Dict) -> unicode
        """Generate a graphviz dot graph from the classes that were passed in
        to __init__.

        *name* is the name of the graph.

        *urls* is a dictionary mapping class names to HTTP URLs.

        *graph_attrs*, *node_attrs*, *edge_attrs* are dictionaries containing
        key/value pairs to pass on as graphviz properties.
        """
        g_attrs = self.default_graph_attrs.copy()
        n_attrs = self.default_node_attrs.copy()
        e_attrs = self.default_edge_attrs.copy()
        c_attrs = self.default_cluster_attrs.copy()
        g_attrs.update(graph_attrs)
        n_attrs.update(node_attrs)
        e_attrs.update(edge_attrs)
        if env:
            g_attrs.update(env.config.inheritance_graph_attrs)
            n_attrs.update(env.config.inheritance_node_attrs)
            e_attrs.update(env.config.inheritance_edge_attrs)
            c_attrs.update(env.config.inheritance_cluster_attrs)

        res = []  # type: List[unicode]
        res.append('digraph %s {\n' % name)
        res.append(self._format_graph_attrs(g_attrs))

        subgraphs = defaultdict(list)  # subgraph_name => list of node names

        for name, fullname, bases, tooltip in sorted(self.class_info):
            subgraph_name = ".".join(fullname.split(".")[:-1])
            subgraphs[subgraph_name].append(name)
            # Write the node
            this_node_attrs = n_attrs.copy()
            if fullname in urls:
                this_node_attrs['URL'] = '"%s"' % urls[fullname]
                this_node_attrs['target'] = '"_top"'
            if tooltip:
                this_node_attrs['tooltip'] = tooltip
            res.append('  "%s" [%s];\n' %
                       (name, self._format_node_attrs(this_node_attrs)))

            # Write the edges
            for base_name in bases:
                res.append('  "%s" -> "%s" [%s];\n' %
                           (base_name, name,
                            self._format_node_attrs(e_attrs)))

        if self.cluster_modules:
            for subgraph_name in subgraphs:
                res.append('subgraph cluster_%s {\n'
                           % subgraph_name.replace('.', '_'))
                res.append('  label="%s";\n' % subgraph_name)
                res.append('  graph[' + self._format_node_attrs(c_attrs) +
                           "];\n")
                res.append('  ' + "; ".join(subgraphs[subgraph_name]) + "\n")
                res.append('}\n')

        res.append('}\n')
        return ''.join(res)