'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={}):

    g_attrs = self.default_graph_attrs.copy()
    n_attrs = self.default_node_attrs.copy()
    e_attrs = self.default_edge_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)
    res = []
    res.append(('digraph    %s    {\n' % name))
    res.append(self._format_graph_attrs(g_attrs))
    for (name, fullname, bases, tooltip) in sorted(self.class_info):
        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))))
        for base_name in bases:
            res.append(('        "%s"    ->    "%s"    [%s];\n' % (base_name, name, self._format_node_attrs(e_attrs))))
    res.append('}\n')
    return ''.join(res)
