Exemple #1
0
 def write_coverage(self, domains):
     status = any(self.undocumented.values())
     if status:
         self.app.statuscode = 2
         print(self.format_undocumented_domains(domains))
     else:
         print(green(OK_STATUS))
Exemple #2
0
 def write_coverage(self, domains):
     status = any(self.undocumented.values())
     if status:
         self.app.statuscode = 2
         print(self.format_undocumented_domains(domains))
     else:
         print(green(OK_STATUS))
Exemple #3
0
    def check_missing(self):
        all_settings = self.project_settings()
        documented_settings = self.documented_settings()
        self.undocumented.update(setting for setting in all_settings
                                 ^ documented_settings
                                 if not self.is_ignored_setting(setting))

        for setting in self.undocumented:
            self.app.statuscode = 2
            print(ERR_MISSING_DOC.format(
                error=red(ERR),
                name=bold(setting),
            ))
        if not self.app.statuscode:
            print(green(OK_STATUS))
Exemple #4
0
    def check_missing(self):
        all_settings = self.project_settings()
        documented_settings = self.documented_settings()
        self.undocumented.update(
            setting for setting in all_settings ^ documented_settings
            if not self.is_ignored_setting(setting)
        )

        for setting in self.undocumented:
            self.app.statuscode = 2
            print(ERR_MISSING_DOC.format(
                error=red(ERR),
                name=bold(setting),
            ))
        if not self.app.statuscode:
            print(green(OK_STATUS))
 def prefix_rewrote(self):
     r'''Messaging prefix for rewritten files.
     '''
     from sphinx.util.console import green
     return green('REWROTE:   ')
Exemple #6
0
def run(app):
    """Run the flowchart generation."""
    fname = op.join(op.dirname(__file__), '..', '_static', 'flow.dot')
    logger.info(console.green(console.bold('creating flowchart')))
    _create_flowchart(fname)
class DocumentationManager(abctools.AbjadObject):
    r'''An API documentation manager.
    '''

    ### CLASS VARIABLES ###

    __documentation_section__ = 'Documenters'

    api_directory_name = 'api'
    api_title = 'Abjad API'
    root_package_name = 'abjad'
    source_directory_path_parts = ('docs', 'source')
    tools_packages_package_path = 'abjad.tools'

    prefix_ignored = lightgray('IGNORED:   ')
    prefix_preserved = darkgray('PRESERVED: ')
    prefix_pruned = red('PRUNED:    ')
    prefix_rewrote = green('REWROTE:   ')
    prefix_wrote = yellow('WROTE:     ')

    ### PRIVATE METHODS ###

    def _build_attribute_section(
        self,
        cls,
        attrs,
        directive,
        title,
    ):
        r'''
        '''
        from abjad.tools import documentationtools
        result = []
        if attrs:
            result.append(documentationtools.ReSTHeading(
                level=3,
                text=title,
            ))
            for attr in attrs:
                options = {
                    'noindex': True,
                }
                autodoc = documentationtools.ReSTAutodocDirective(
                    argument='{}.{}'.format(cls.__name__, attr.name),
                    directive=directive,
                    options=options,
                )
                if cls is attr.defining_class:
                    result.append(autodoc)
                else:
                    container = documentationtools.ReSTDirective(
                        argument='inherited',
                        directive='container',
                    )
                    container.append(autodoc)
                    html_only = documentationtools.ReSTDirective(
                        argument='html',
                        directive='only',
                    )
                    html_only.append(container)
                    result.append(html_only)
        return result

    def _build_attributes_autosummary(
        self,
        cls,
        class_methods,
        data,
        inherited_attributes,
        methods,
        readonly_properties,
        readwrite_properties,
        special_methods,
        static_methods,
    ):
        r'''
        '''
        from abjad.tools import documentationtools
        result = []
        attributes = []
        attributes.extend(readonly_properties)
        attributes.extend(readwrite_properties)
        attributes.extend(methods)
        attributes.extend(class_methods)
        attributes.extend(static_methods)
        attributes.sort(key=lambda x: x.name)
        attributes.extend(special_methods)
        if attributes:
            autosummary = documentationtools.ReSTAutosummaryDirective()
            for attribute in attributes:
                autosummary.append('~{}.{}.{}'.format(
                    cls.__module__,
                    cls.__name__,
                    attribute.name,
                ))
            html_only = documentationtools.ReSTOnlyDirective(argument='html')
            html_only.append(
                documentationtools.ReSTHeading(
                    level=3,
                    text='Attribute summary',
                ))
            html_only.append(autosummary)
            result.append(html_only)
        return result

    def _build_bases_section(self, cls):
        from abjad.tools import documentationtools
        result = []
        result.append(documentationtools.ReSTHeading(
            level=3,
            text='Bases',
        ))
        mro = inspect.getmro(cls)[1:]
        for cls in mro:
            parts = cls.__module__.split('.') + [cls.__name__]
            while 1 < len(parts) and parts[-1] == parts[-2]:
                parts.pop()
            packagesystem_path = '.'.join(parts)
            text = '- :py:class:`{}`'.format(packagesystem_path)
            paragraph = documentationtools.ReSTParagraph(
                text=text,
                wrap=False,
            )
            result.append(paragraph)
        return result

    def _build_enumeration_section(self, cls):
        from abjad.tools import documentationtools
        result = []
        if not issubclass(cls, enum.Enum):
            return result
        items = sorted(cls, key=lambda x: x.name)
        if items:
            result.append(
                documentationtools.ReSTHeading(
                    level=3,
                    text='Enumeration Items',
                ))
            for item in items:
                name = item.name
                value = item.value
                line = '- `{}`: {}'.format(name, value)
                paragraph = documentationtools.ReSTParagraph(
                    text=line,
                    wrap=False,
                )
                result.append(paragraph)
        return result

    def _collect_class_attributes(self, cls):
        ignored_special_methods = (
            '__getattribute__',
            '__getnewargs__',
            '__getstate__',
            '__init__',
            '__reduce__',
            '__reduce_ex__',
            '__setstate__',
            '__sizeof__',
            '__subclasshook__',
            'fromkeys',
            'pipe_cloexec',
        )
        class_methods = []
        data = []
        inherited_attributes = []
        methods = []
        readonly_properties = []
        readwrite_properties = []
        special_methods = []
        static_methods = []
        attrs = inspect.classify_class_attrs(cls)
        for attr in attrs:
            if attr.defining_class is object:
                continue
            if attr.defining_class is not cls:
                inherited_attributes.append(attr)
            if attr.kind == 'method':
                if attr.name not in ignored_special_methods:
                    if attr.name.startswith('__'):
                        special_methods.append(attr)
                    elif not attr.name.startswith('_'):
                        methods.append(attr)
            elif attr.kind == 'class method':
                if attr.name not in ignored_special_methods:
                    if attr.name.startswith('__'):
                        special_methods.append(attr)
                    elif not attr.name.startswith('_'):
                        class_methods.append(attr)
            elif attr.kind == 'static method':
                if attr.name not in ignored_special_methods:
                    if attr.name.startswith('__'):
                        special_methods.append(attr)
                    elif not attr.name.startswith('_'):
                        static_methods.append(attr)
            elif attr.kind == 'property' and not attr.name.startswith('_'):
                if attr.object.fset is None:
                    readonly_properties.append(attr)
                else:
                    readwrite_properties.append(attr)
            elif attr.kind == 'data' and not attr.name.startswith('_') \
                and attr.name not in getattr(cls, '__slots__', ()):
                data.append(attr)
        class_methods = tuple(sorted(class_methods))
        data = tuple(sorted(data))
        inherited_attributes = tuple(sorted(inherited_attributes))
        methods = tuple(sorted(methods))
        readonly_properties = tuple(sorted(readonly_properties))
        readwrite_properties = tuple(sorted(readwrite_properties))
        special_methods = tuple(sorted(special_methods))
        static_methods = tuple(sorted(static_methods))
        result = (
            class_methods,
            data,
            inherited_attributes,
            methods,
            readonly_properties,
            readwrite_properties,
            special_methods,
            static_methods,
        )
        return result

    def _ensure_directory(self, path):
        path = os.path.dirname(path)
        if not os.path.exists(path):
            os.makedirs(path)

    def _get_api_directory_path(self, source_directory):
        if self.api_directory_name:
            path = os.path.join(
                source_directory,
                self.api_directory_name,
            )
        else:
            path = source_directory
        return path

    def _get_api_index_file_path(self, source_directory):
        if self.api_directory_name:
            directory_path = os.path.join(
                source_directory,
                self.api_directory_name,
            )
        else:
            directory_path = source_directory
        api_index_path = os.path.join(
            directory_path,
            'index.rst',
        )
        return api_index_path

    def _get_api_index_rst(self, tools_packages):
        r'''
        '''
        from abjad.tools import documentationtools
        document = documentationtools.ReSTDocument()
        heading = documentationtools.ReSTHeading(
            level=2,
            text=self.api_title,
        )
        document.append(heading)
        toc = documentationtools.ReSTTOCDirective(options={
            'maxdepth': 3,
            'includehidden': True,
        }, )
        for tools_package in tools_packages:
            tools_package_parts = tools_package.__package__.split('.')[1:]
            tools_package_path = '/'.join(tools_package_parts)
            toc_item = documentationtools.ReSTTOCItem(
                text='{}/index'.format(tools_package_path), )
            toc.append(toc_item)
        document.append(toc)
        return document

    def _get_class_rst(self, cls):
        import abjad
        module_name, _, class_name = cls.__module__.rpartition('.')
        tools_package_python_path = '.'.join(cls.__module__.split('.')[:-1])
        (
            class_methods,
            data,
            inherited_attributes,
            methods,
            readonly_properties,
            readwrite_properties,
            special_methods,
            static_methods,
        ) = self._collect_class_attributes(cls)
        document = abjad.documentationtools.ReSTDocument()
        module_directive = abjad.documentationtools.ReSTDirective(
            directive='currentmodule',
            argument=tools_package_python_path,
        )
        document.append(module_directive)
        heading = abjad.documentationtools.ReSTHeading(
            level=2,
            text=class_name,
        )
        document.append(heading)
        autoclass_directive = abjad.documentationtools.ReSTAutodocDirective(
            argument=cls.__name__,
            directive='autoclass',
        )
        document.append(autoclass_directive)
        try:
            lineage_heading = abjad.documentationtools.ReSTHeading(
                level=3,
                text='Lineage',
            )
            document.append(lineage_heading)
            lineage_graph = self._get_lineage_graph(cls)
            lineage_graph.attributes['background'] = 'transparent'
            lineage_graph.attributes['rankdir'] = 'LR'
            graphviz_directive = \
                abjad.documentationtools.ReSTGraphvizDirective(
                    graph=lineage_graph,
                    )
            graphviz_container = abjad.documentationtools.ReSTDirective(
                directive='container',
                argument='graphviz',
            )
            graphviz_container.append(graphviz_directive)
            document.append(graphviz_container)
        except:
            traceback.print_exc()
        document.extend(self._build_bases_section(cls))
        document.extend(self._build_enumeration_section(cls))
        document.extend(
            self._build_attributes_autosummary(
                cls,
                class_methods,
                data,
                inherited_attributes,
                methods,
                readonly_properties,
                readwrite_properties,
                special_methods,
                static_methods,
            ))
        document.extend(
            self._build_attribute_section(
                cls,
                readonly_properties,
                'autoattribute',
                'Read-only properties',
            ))
        document.extend(
            self._build_attribute_section(
                cls,
                readwrite_properties,
                'autoattribute',
                'Read/write properties',
            ))
        document.extend(
            self._build_attribute_section(
                cls,
                methods,
                'automethod',
                'Methods',
            ))
        document.extend(
            self._build_attribute_section(
                cls,
                sorted(
                    class_methods + static_methods,
                    key=lambda x: x.name,
                ),
                'automethod',
                'Class & static methods',
            ))
        #        document.extend(self._build_attribute_section(
        #            cls,
        #            class_methods,
        #            'automethod',
        #            'Class methods',
        #            ))
        #        document.extend(self._build_attribute_section(
        #            cls,
        #            static_methods,
        #            'automethod',
        #            'Static methods',
        #            ))
        document.extend(
            self._build_attribute_section(
                cls,
                special_methods,
                'automethod',
                'Special methods',
            ))
        return document

    def _get_class_summary(self, cls):
        r'''
        '''
        doc = cls.__doc__
        if doc is None:
            doc = ''
        doc = doc.splitlines()
        m = re.search(r"^([A-Z].*?\.)(?:\s|$)", " ".join(doc).strip())
        if m:
            summary = m.group(1).strip()
        elif doc:
            summary = doc[0].strip()
        else:
            summary = ''
        return summary

    def _get_function_rst(self, function):
        r'''
        '''
        import abjad
        document = abjad.documentationtools.ReSTDocument()
        tools_package_python_path = '.'.join(
            function.__module__.split('.')[:-1])
        module_directive = abjad.documentationtools.ReSTDirective(
            directive='currentmodule',
            argument=tools_package_python_path,
        )
        document.append(module_directive)
        heading = abjad.documentationtools.ReSTHeading(
            level=2,
            text=function.__name__,
        )
        document.append(heading)
        autodoc_directive = abjad.documentationtools.ReSTAutodocDirective(
            argument=function.__name__,
            directive='autofunction',
        )
        document.append(autodoc_directive)
        return document

    def _get_ignored_classes(self):
        from abjad.tools import abjadbooktools
        ignored_classes = set([
            abjadbooktools.abjad_import_block,
            abjadbooktools.abjad_input_block,
            abjadbooktools.abjad_output_block,
            abjadbooktools.abjad_thumbnail_block,
        ])
        return ignored_classes

    def _get_tools_package_graph(self, tools_package):
        from abjad.tools import documentationtools
        inheritance_graph = documentationtools.InheritanceGraph(
            lineage_addresses=[tools_package.__package__])
        lineage_graph = inheritance_graph.__graph__()
        lineage_graph.attributes['background'] = 'transparent'
        lineage_graph.attributes['rankdir'] = 'LR'
        return lineage_graph

    def _get_lineage_graph(self, cls):
        def get_node_name(original_name):
            parts = original_name.split('.')
            name = [parts[0]]
            for part in parts[1:]:
                if part != name[-1]:
                    name.append(part)
            if name[0] in ('abjad', 'experimental', 'ide'):
                return str('.'.join(name[2:]))
            return str('.'.join(name))

        from abjad.tools import documentationtools
        addresses = ('abjad', 'experimental', 'ide')
        module_name, _, class_name = cls.__module__.rpartition('.')
        node_name = get_node_name(module_name + '.' + class_name)
        importlib.import_module(module_name)
        lineage = documentationtools.InheritanceGraph(
            addresses=addresses,
            lineage_addresses=((module_name, class_name), ))
        graph = lineage.__graph__()
        maximum_node_count = 30
        if maximum_node_count < len(graph.leaves):
            lineage = documentationtools.InheritanceGraph(
                addresses=addresses,
                lineage_addresses=((module_name, class_name), ),
                lineage_prune_distance=2,
            )
            graph = lineage.__graph__()
        if maximum_node_count < len(graph.leaves):
            lineage = documentationtools.InheritanceGraph(
                addresses=addresses,
                lineage_addresses=((module_name, class_name), ),
                lineage_prune_distance=1,
            )
            graph = lineage.__graph__()
        if maximum_node_count < len(graph.leaves):
            lineage = documentationtools.InheritanceGraph(
                addresses=((module_name, class_name), ), )
            graph = lineage.__graph__()
            graph_node = graph[node_name]
            graph_node.attributes['color'] = 'black'
            graph_node.attributes['fontcolor'] = 'white'
            graph_node.attributes['style'] = ('filled', 'rounded')
        graph_node = graph[node_name]
        graph_node.attributes['label'] = \
            '<<B>{}</B>>'.format(graph_node.attributes['label'])
        return graph

    def _get_source_directory(self):
        root_package = importlib.import_module(self.root_package_name)
        root_package_path = root_package.__path__[0]
        path_parts = [root_package_path]
        path_parts.extend(self.source_directory_path_parts)
        source_directory = os.path.join(*path_parts)
        return source_directory

    def _get_tools_packages(self):
        r'''
        '''
        root_module = self._get_root_module()
        tools_packages_module = self._get_tools_packages_module()
        tools_packages = []
        for name in dir(tools_packages_module):
            if name.startswith('_'):
                continue
            module = getattr(tools_packages_module, name)
            if not isinstance(module, types.ModuleType):
                continue
            if not module.__package__.startswith(root_module.__package__):
                continue
            tools_packages.append(module)
        tools_packages.sort(key=lambda x: x.__name__)
        tools_packages = tuple(tools_packages)
        return tools_packages

    def _get_root_module(self):
        r'''
        '''
        root_module = importlib.import_module(self.root_package_name)
        return root_module

    def _get_tools_packages_module(self):
        r'''
        '''
        tools_packages_module = importlib.import_module(
            self.tools_packages_package_path)
        return tools_packages_module

    def _get_tools_package_contents(self, tools_package):
        r'''
        '''
        classes = []
        functions = []
        for name in dir(tools_package):
            if name.startswith('_'):
                continue
            obj = getattr(tools_package, name)
            if not hasattr(obj, '__module__'):
                print('Warning: no nominative object in {}'.format(obj))
                continue
            if not obj.__module__.startswith(tools_package.__package__):
                continue
            if isinstance(obj, type):
                classes.append(obj)
            elif isinstance(obj, types.FunctionType):
                functions.append(obj)
        classes.sort(key=lambda x: x.__name__)
        classes = tuple(classes)
        functions.sort(key=lambda x: x.__name__)
        functions = tuple(functions)
        return classes, functions

    def _get_tools_package_rst(self, tools_package):
        r'''
        '''
        from abjad.tools import documentationtools
        classes, functions = self._get_tools_package_contents(tools_package, )
        document = documentationtools.ReSTDocument()
        heading = documentationtools.ReSTHeading(
            level=2,
            text=tools_package.__name__.split('.')[-1],
        )
        document.append(heading)
        automodule_directive = documentationtools.ReSTAutodocDirective(
            argument=tools_package.__name__,
            directive='automodule',
        )
        document.append(automodule_directive)
        ignored_classes = self._get_ignored_classes()
        classes = [_ for _ in classes if _ not in ignored_classes]
        if classes:
            rule = documentationtools.ReSTHorizontalRule()
            document.append(rule)
            lineage_heading = documentationtools.ReSTHeading(
                level=3,
                text='Lineage',
            )
            document.append(lineage_heading)
            lineage_graph = self._get_tools_package_graph(tools_package)
            graphviz_directive = documentationtools.ReSTGraphvizDirective(
                graph=lineage_graph, )
            graphviz_container = documentationtools.ReSTDirective(
                directive='container',
                argument='graphviz',
            )
            graphviz_container.append(graphviz_directive)
            document.append(graphviz_container)
        if classes:
            sections = {}
            for cls in classes:
                documentation_section = getattr(
                    cls,
                    '__documentation_section__',
                    None,
                )
                if documentation_section is None:
                    if issubclass(cls, enum.Enum):
                        documentation_section = 'Enumerations'
                    elif issubclass(cls, Exception):
                        documentation_section = 'Errors'
                    else:
                        documentation_section = 'Classes'
                    if inspect.isabstract(cls):
                        documentation_section = 'Abstract Classes'
                if documentation_section not in sections:
                    sections[documentation_section] = []
                sections[documentation_section].append(cls)
            section_names = sorted(sections)
            if 'Main Classes' in sections:
                section_names.remove('Main Classes')
                section_names.insert(0, 'Main Classes')
            if 'Errors' in sections:
                section_names.remove('Errors')
                section_names.append('Errors')
            for section_name in section_names:
                rule = documentationtools.ReSTHorizontalRule()
                document.append(rule)
                heading = documentationtools.ReSTHeading(
                    level=3,
                    text=section_name,
                )
                #heading = documentationtools.ReSTDirective(
                #    directive='rubric',
                #    argument=section_name,
                #    )
                document.append(heading)
                toc = documentationtools.ReSTTOCDirective(
                    options={
                        #'caption': section_name,
                        'hidden': True,
                        #'name': '{}__{}'.format(
                        #    tools_package.__name__,
                        #    section_name,
                        #    ),
                    }, )
                for cls in sections[section_name]:
                    class_name = cls.__name__
                    if class_name == 'Index':
                        class_name = '_Index'
                    toc_item = documentationtools.ReSTTOCItem(
                        text=class_name, )
                    toc.append(toc_item)
                document.append(toc)
                autosummary = documentationtools.ReSTAutosummaryDirective(
                    options={
                        'nosignatures': True,
                    }, )
                for cls in sections[section_name]:
                    item = documentationtools.ReSTAutosummaryItem(
                        text=cls.__name__, )
                    autosummary.append(item)
                document.append(autosummary)
        if functions:
            if classes:
                rule = documentationtools.ReSTHorizontalRule()
                document.append(rule)
            section_name = 'Functions'
            heading = documentationtools.ReSTHeading(
                level=3,
                text=section_name,
            )
            #heading = documentationtools.ReSTDirective(
            #    directive='rubric',
            #    argument=section_name,
            #    )
            document.append(heading)
            toc = documentationtools.ReSTTOCDirective(
                options={
                    #'caption': section_name,
                    'hidden': True,
                    #'name': '{}__{}'.format(
                    #    tools_package.__name__,
                    #    section_name,
                    #    ),
                }, )
            for function in functions:
                toc_item = documentationtools.ReSTTOCItem(
                    text=function.__name__, )
                toc.append(toc_item)
            document.append(toc)
            autosummary = documentationtools.ReSTAutosummaryDirective(options={
                'nosignatures':
                True,
            }, )
            for function in functions:
                item = documentationtools.ReSTAutosummaryItem(
                    text=function.__name__, )
                autosummary.append(item)
            document.append(autosummary)
        return document

    def _module_path_to_file_path(self, module_path, source_directory):
        r'''
        '''
        parts = module_path.split('.')
        parts = parts[1:]
        if parts[-1] == 'Index':
            parts[-1] = '_' + parts[-1] + '.rst'
        else:
            parts[-1] = parts[-1] + '.rst'
        parts.insert(0, self._get_api_directory_path(source_directory))
        path = os.path.join(*parts)
        return path

    def _package_path_to_file_path(self, package_path, source_directory):
        r'''
        '''
        parts = package_path.split('.')
        parts = parts[1:]
        parts.append('index.rst')
        parts.insert(0, self._get_api_directory_path(source_directory))
        path = os.path.join(*parts)
        return path

    def _remove_api_directory(self):
        r'''
        '''
        path = self._get_api_directory_path()
        if os.path.exists(path):
            shutil.rmtree(path)

    def _write(self, file_path, string, rewritten_files):
        r'''
        '''
        should_write = True
        if os.path.exists(file_path):
            with open(file_path, 'r') as file_pointer:
                old_string = file_pointer.read()
            if old_string == string:
                should_write = False
        if should_write:
            if os.path.exists(file_path):
                print('{}{}'.format(
                    self.prefix_rewrote,
                    os.path.relpath(file_path),
                ))
            else:
                print('{}{}'.format(
                    self.prefix_wrote,
                    os.path.relpath(file_path),
                ))
            with open(file_path, 'w') as file_pointer:
                file_pointer.write(string)
        else:
            print('{}{}'.format(
                self.prefix_preserved,
                os.path.relpath(file_path),
            ))
        rewritten_files.add(file_path)

    ### PUBLIC METHODS ###

    def execute(self):
        r'''Executes documentation manager.
        '''
        print('Rebuilding documentation source.')
        source_directory = self._get_source_directory()
        with systemtools.TemporaryDirectoryChange(
                directory=source_directory,
                verbose=True,
        ):
            rewritten_files = set()
            tools_packages = self._get_tools_packages()
            api_index_rst = self._get_api_index_rst(tools_packages)
            api_index_file_path = self._get_api_index_file_path(
                source_directory)
            self._ensure_directory(api_index_file_path)
            self._write(
                api_index_file_path,
                api_index_rst.rest_format,
                rewritten_files,
            )
            ignored_classes = self._get_ignored_classes()
            for package in tools_packages:
                tools_package_rst = self._get_tools_package_rst(package)
                tools_package_file_path = self._package_path_to_file_path(
                    package.__package__,
                    source_directory,
                )
                self._ensure_directory(tools_package_file_path)
                self._write(
                    tools_package_file_path,
                    tools_package_rst.rest_format,
                    rewritten_files,
                )
                classes, functions = \
                    self._get_tools_package_contents(package)
                for cls in classes:
                    file_path = self._module_path_to_file_path(
                        cls.__module__,
                        source_directory,
                    )
                    if cls in ignored_classes:
                        print('{}{}'.format(
                            self.prefix_ignored,
                            os.path.relpath(file_path),
                        ))
                        continue
                    rst = self._get_class_rst(cls)
                    self._write(file_path, rst.rest_format, rewritten_files)
                for function in functions:
                    file_path = self._module_path_to_file_path(
                        function.__module__,
                        source_directory,
                    )
                    rst = self._get_function_rst(function)
                    self._write(file_path, rst.rest_format, rewritten_files)
            for root, directory_names, file_names in os.walk(
                    self._get_api_directory_path(source_directory),
                    topdown=False,
            ):
                for file_name in file_names[:]:
                    file_path = os.path.join(root, file_name)
                    if not file_path.endswith('.rst'):
                        continue
                    if file_path not in rewritten_files:
                        file_names.remove(file_name)
                        os.remove(file_path)
                        print('{}{}'.format(
                            self.prefix_pruned,
                            os.path.relpath(file_path),
                        ))
                if not file_names and not directory_names:
                    shutil.rmtree(root)
                    print('{}{}'.format(
                        self.prefix_pruned,
                        os.path.relpath(root),
                    ))

    @staticmethod
    def make_readme():
        r'''Creates README.rst file.
        '''
        import abjad
        abjad_path = abjad.__path__[0]
        version = abjad.__version__
        docs_path = os.path.join(abjad_path, 'docs', 'source')
        abstract_path = os.path.join(docs_path, 'abstract.txt')
        badges_path = os.path.join(docs_path, 'badges.txt')
        links_path = os.path.join(docs_path, 'links.txt')
        installation_path = os.path.join(docs_path, 'installation.rst')
        result = 'Abjad {}'.format(version)
        result = ['#' * len(result), result, '#' * len(result)]
        with open(abstract_path, 'r') as file_pointer:
            result.append('')
            result.append(file_pointer.read())
        with open(links_path, 'r') as file_pointer:
            result.append('')
            result.append(file_pointer.read())
        with open(badges_path, 'r') as file_pointer:
            result.append('')
            result.append(file_pointer.read())
        with open(installation_path, 'r') as file_pointer:
            result.append('')
            result.append(file_pointer.read())
        result = '\n'.join(result)
        readme_path = os.path.join(abjad_path, '..', 'README.rst')
        with open(readme_path, 'w') as file_pointer:
            file_pointer.write(result)