# Buggy code
def search_module_help(text):
    """
    Search the help for a string

    :param text: find text in the module help using case-insensitive matching
    :return: an html document of all the module help pages that matched or None if no match found.
    """
    matching_help = []

    count = 0

    for menu_item, help_text in MENU_HELP.iteritems():
        help_text = cellprofiler.gui.html.utils.rst_to_html_fragment(help_text)

        matches = __search_fn(help_text, text)

        if len(matches) > 0:
            matching_help.append((menu_item, help_text, matches))

            count += len(matches)

    for module_name in cellprofiler.modules.get_module_names():
        module = cellprofiler.modules.instantiate_module(module_name)

        location = os.path.split(module.create_settings.im_func.func_code.co_filename)[
            0
        ]

        if location == cellprofiler.preferences.get_plugin_directory():
            continue

        help_text = module.get_help()

        matches = __search_fn(help_text, text)

        if len(matches) > 0:
            matching_help.append((module_name, help_text, matches))

            count += len(matches)

    if len(matching_help) == 0:
        return None

    top = """\
<html style="font-family:arial">
<head>
    <title>{count} match{es} found</title>
</head>
<body>
    <h1>Match{es} found</h1><br>
    <ul></ul>
</body>
</html>
""".format(**{"count": count, "es": "" if count == 1 else "es"})

    body = "<br>"

    match_num = 1

    prev_link = """\
<a href="#match%d" title="Previous match">
    <img alt="previous match" src=memory:previous.png">
</a>"""

    anchor = """<a name="match%d"><u>%s</u></a>"""

    next_link = """<a href="#match%d" title="Next match"><img src="memory:next.png" alt="next match"></a>"""

    for title, help_text, pairs in matching_help:
        top += """<li><a href="#match{:d}">{}</a></li>\n""".format(match_num, title)

        if help_text.find("<h1>") == -1:
            body += "<h1>{}</h1>".format(title)

        start_match = re.search(r"<\s*body[^>]*?>", help_text, re.IGNORECASE)

        if start_match is None:
            start = 0
        else:
            start = start_match.end()

        end_match = re.search(r"<\\\s*body", help_text, re.IGNORECASE)

        if end_match is None:
            end = len(help_text)
        else:
            end = end_match.start()

        for begin_pos, end_pos in pairs:
            body += help_text[start:begin_pos]

            if match_num > 1:
                body += prev_link % (match_num - 1)

            body += anchor % (match_num, help_text[begin_pos:end_pos])

            if match_num != count:
                body += next_link % (match_num + 1)

            start = end_pos

            match_num += 1

        body += help_text[start:end] + "<br>"

    result = "{}</ul><br>\n{}</body></html>".format(top, body)

    return result


# Traceback (AttributeError)
Traceback (most recent call last):
File "cellprofiler\gui\help\search.py", line 129, in <lambda>
lambda _: __on_search(self.results_view)
File "cellprofiler\gui\help\search.py", line 89, in __on_search
html = search_module_help(search_text)
File "cellprofiler\gui\help\search.py", line 234, in search_module_help
help_text = module.get_help()
File "cellprofiler\module.py", line 255, in get_help
"MODULE_DOC": self._rst_to_html_fragment(self.__doc__),
File "cellprofiler\module.py", line 212, in _rst_to_html_fragment
parts = docutils.core.publish_parts(source=source, writer_name="html")
File "C:\Python27\lib\site-packages\docutils\core.py", line 448, in publish_parts
enable_exit_status=enable_exit_status)
File "C:\Python27\lib\site-packages\docutils\core.py", line 662, in publish_programmatically
output = pub.publish(enable_exit_status=enable_exit_status)
File "C:\Python27\lib\site-packages\docutils\core.py", line 217, in publish
self.settings)
File "C:\Python27\lib\site-packages\docutils\readers\__init__.py", line 71, in read
self.input = self.source.read()
File "C:\Python27\lib\site-packages\docutils\io.py", line 426, in read
return self.decode(self.source)
File "C:\Python27\lib\site-packages\docutils\io.py", line 99, in decode
data_encoding = self.determine_encoding_from_data(data)
File "C:\Python27\lib\site-packages\docutils\io.py", line 142, in determine_encoding_from_data
if data.startswith(start_bytes):
AttributeError: 'NoneType' object has no attribute 'startswith'

# Fixed code
def search_module_help(text):
    """
    Search the help for a string

    :param text: find text in the module help using case-insensitive matching
    :return: an html document of all the module help pages that matched or None if no match found.
    """
    matching_help = []

    count = 0

    for menu_item, help_text in MENU_HELP.iteritems():
        help_text = cellprofiler.gui.html.utils.rst_to_html_fragment(help_text)

        matches = __search_fn(help_text, text)

        if len(matches) > 0:
            matching_help.append((menu_item, help_text, matches))

            count += len(matches)

    for module_name in cellprofiler.modules.get_module_names():
        module = cellprofiler.modules.instantiate_module(module_name)

        location = os.path.split(module.create_settings.im_func.func_code.co_filename)[
            0
        ]

        if location == cellprofiler.preferences.get_plugin_directory():
            continue

        help_text = module.get_help()

        matches = __search_fn(help_text, text)

        if len(matches) > 0:
            matching_help.append((module_name, help_text, matches))

            count += len(matches)

    if len(matching_help) == 0:
        return None

    top = """\
<html style="font-family:arial">
<head>
    <title>{count} match{es} found</title>
</head>
<body>
    <h1>Match{es} found ({count} total)</h1><br>
    <ul></ul>
</body>
</html>
""".format(**{"count": count, "es": "" if count == 1 else "es"})

    body = "<br>"

    match_num = 1

    prev_link = """<a href="#match%d" title="Previous match"><img alt="previous match" src="memory:previous.png"></a>"""

    anchor = """<a name="match%d"><u>%s</u></a>"""

    next_link = """<a href="#match%d" title="Next match"><img src="memory:next.png" alt="next match"></a>"""

    for title, help_text, pairs in matching_help:
        top += """<li><a href="#match{:d}">{}</a></li>\n""".format(match_num, title)

        start_match = re.search(r"<\s*body[^>]*?>", help_text, re.IGNORECASE)

        # Some pages don't have in-line titles
        # Not matching "<h1>" here for cases that have "<h1 class='title'>", etc.
        if not help_text.startswith("<h1"):
            body += "<h1>{}</h1>".format(title)

        if start_match is None:
            start = 0
        else:
            start = start_match.end()

        end_match = re.search(r"<\\\s*body", help_text, re.IGNORECASE)

        if end_match is None:
            end = len(help_text)
        else:
            end = end_match.start()

        for begin_pos, end_pos in pairs:
            body += help_text[start:begin_pos]

            if match_num > 1:
                body += prev_link % (match_num - 1)

            body += anchor % (match_num, help_text[begin_pos:end_pos])

            if match_num != count:
                body += next_link % (match_num + 1)

            start = end_pos

            match_num += 1

        body += help_text[start:end] + "<br>"

    result = "{}</ul><br>\n{}</body></html>".format(top, body)

    return result