Repository: pyinstaller/pyinstaller

Issue:
Always write modulegraph xref and document it
**very easy task**

We currently write the modulegraph xref (as html) only if the log-level is greater then DEBUG (`_write_warnings` in PyInstaller/building/build_main.py).

The xref (as html) is much more usable and useful than the `warnfile.txt`. One can see which modules have been searched for and by which modules. Thus the xref-hml should be always written – the dot-file can be left at "> DEBUG" or be changed to ">= DEBUG".

In the documentation, esp. the wiki, esp. "Make sure everything is packaged correctly" this file should be referenced and this should be done much more prominently than for the warnfile.txt.


Discussion:
It just came to my mind that we should have this in 3.4 already, so we can benefit from it in the next release-cycle already.

Resolving patch:
diff --git a/PyInstaller/building/build_main.py b/PyInstaller/building/build_main.py
--- a/PyInstaller/building/build_main.py
+++ b/PyInstaller/building/build_main.py
@@ -582,17 +582,18 @@ def _write_warnings(self):
             logger.info("Warnings written to %s", CONF['warnfile'])
 
     def _write_graph_debug(self):
-        # With `--log-level DEBUG` write a xref and a dot-drawing of
-        # the graph.
+        """Write a xref (in html) and with `--log-level DEBUG` a dot-drawing
+        of the graph.
+        """
+        from ..config import CONF
+        with open(CONF['xref-file'], 'w') as fh:
+            self.graph.create_xref(fh)
+            logger.info("Graph cross-reference written to %s", CONF['xref-file'])
         if logger.getEffectiveLevel() > logging.DEBUG:
             return
-        from ..config import CONF
         with open(CONF['dot-file'], 'w') as fh:
             self.graph.graphreport(fh)
             logger.info("Graph drawing written to %s", CONF['dot-file'])
-        with open(CONF['xref-file'], 'w') as fh:
-            self.graph.create_xref(fh)
-            logger.info("Graph cross-reference written to %s", CONF['xref-file'])
 
 
     def _check_python_library(self, binaries):
diff --git a/PyInstaller/lib/modulegraph/modulegraph.py b/PyInstaller/lib/modulegraph/modulegraph.py
--- a/PyInstaller/lib/modulegraph/modulegraph.py
+++ b/PyInstaller/lib/modulegraph/modulegraph.py
@@ -849,18 +849,20 @@ def __init__(self, *args, **kwds):
   <head>
     <title>%(TITLE)s</title>
     <style>
-      .node { margin:1em 0; }
+      .node { padding: 0.5em 0 0.5em; border-top: thin grey dotted; }
       .moduletype { font: smaller italic }
+      .node a { text-decoration: none; color: #006699; }
+      .node a:visited { text-decoration: none; color: #2f0099; }
     </style>
   </head>
   <body>
     <h1>%(TITLE)s</h1>"""
 entry = """
 <div class="node">
-  <a name="%(NAME)s" />
+  <a name="%(NAME)s"></a>
   %(CONTENT)s
 </div>"""
-contpl = """<tt>%(NAME)s</tt> %(TYPE)s"""
+contpl = """<tt>%(NAME)s</tt> <span class="moduletype">%(TYPE)s</span>"""
 contpl_linked = """\
 <a target="code" href="%(URL)s" type="text/plain"><tt>%(NAME)s</tt></a>
 <span class="moduletype">%(TYPE)s</span>"""
@@ -3093,14 +3095,22 @@ def sorted_namelist(mods):
                                            'TYPE': m.__class__.__name__}
             oute, ince = map(sorted_namelist, self.get_edges(m))
             if oute:
-                links = ""
+                links = []
                 for n in oute:
-                    links += """  <a href="#%s">%s</a>\n""" % (n, n)
+                    links.append("""  <a href="#%s">%s</a>\n""" % (n, n))
+                # #8226 = bullet-point; can't use html-entities since the
+                # test-suite uses xml.etree.ElementTree.XMLParser, which
+                # does't supprot them.
+                links = " &#8226; ".join(links)
                 content += imports % {"HEAD": "imports", "LINKS": links}
             if ince:
-                links = ""
+                links = []
                 for n in ince:
-                    links += """  <a href="#%s">%s</a>\n""" % (n, n)
+                    links.append("""  <a href="#%s">%s</a>\n""" % (n, n))
+                # #8226 = bullet-point; can't use html-entities since the
+                # test-suite uses xml.etree.ElementTree.XMLParser, which
+                # does't supprot them.
+                links = " &#8226; ".join(links)
                 content += imports % {"HEAD": "imported by", "LINKS": links}
             print(entry % {"NAME": name,"CONTENT": content}, file=out)
         print(footer, file=out)


Test patch: