summaryrefslogtreecommitdiff
path: root/sphinxutils.py
blob: 295d4074c3c15b6dce74cd49f2afe9c462b11243 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
"""
Sphinx utils:

* ModuleGenerator: Generate a file that lists all the modules of a list of
    packages in order to pull all the docstring.
    /!\ This should not be used in a makefile to systematically generate
    sphinx documentation!
"""

import os, sys
import os.path as osp


class ModuleGenerator:

    file_header = """.. -*- coding: utf-8 -*- \n\n%s\n"""
    def __init__(self, project_title, code_dir, dest_file):
        self.main_dir = code_dir
        self.dest_file = dest_file
        self.set_docdir()
        self.mod_names = []
        self.title = project_title

    def set_docdir(self, subfolder =""):
        """set the directory for the destination path"""
        self.output_fn = osp.join(self.main_dir, subfolder, self.dest_file)

    def make(self, mod_names, exclude_dirs):
        """make the module file"""
        self.mod_names = [osp.join(self.main_dir, name) for name in mod_names]
        self.exclude_dirs = exclude_dirs
        self.fn = open(self.output_fn, 'w')
        num = len(self.title) + 6
        title = "=" * num + "\n %s API\n" % self.title + "=" * num
        self.fn.write(self.file_header % title)
        self.find_modules()
        self.gen_modules()
        self.fn.close()

    def gen_modules(self):
        """generate all modules"""
        for mod_name in self.find_modules():
            mod_entry = """
:mod:`%s`
%s

.. automodule:: %s
   :members:
""" % (mod_name, '='*(len(':mod:``' + mod_name)), mod_name)
            self.fn.write(mod_entry)

    def find_modules(self):
        """find all python modules to be documented"""
        modules = []
        for mod_name in self.mod_names:
            for root, dirs, files in os.walk(mod_name):
                if not self.keep_module(root):
                    continue
                for name in files:
                    if name == "__init__.py":
                        self._handle_module(root, mod_name, modules)
                    elif (name.endswith(".py") and name != "__pkginfo__.py"
                          and "__init__.py" in files):
                        filename = osp.join(root, name.split('.py')[0])
                        self._handle_module(filename, mod_name, modules)
        return modules

    def _handle_module(self, filename, modname, modules):
        """handle a module"""
        if self.format_mod_name(filename, modname) not in modules:
            modules.append(self.format_mod_name(filename, modname))

    def format_mod_name(self, path, mod_name):
        mod_root = mod_name.split('/')[-1]
        mod_end = path.split(mod_root)[-1]
        return mod_root + mod_end.replace('/', '.')

    def keep_module(self, mod_end):
        """Filter modules in order to exclude specific package directories"""
        for dir in self.exclude_dirs:
            if mod_end.find(dir) != -1:
                return False
        return True


def generate_modules_file(args):
    """generate all module files"""
    # TODO : use lgc options
    if len(args) != 3:

        print """
Two arguments required:
    generate_modules [project-title] [code-dir] [file-out]

[project-title] : title of the project to be documented
[code-dir] : full path to the code directory
[file-out] : rest file containing the list of modules for Sphinx
"""
        sys.exit()
    project_title = args[0]
    code_dir = args[1]
    destfile = args[2]
    mg = ModuleGenerator(project_title, code_dir, destfile)
    return mg

if __name__ == '__main__':
    # example :
    mg = generate_modules_file(sys.argv[1:])
    modnames = ['logilab']
    exclude = ('test', 'tests', 'examples', 'data', 'doc', '.hg', 'migration')
    mg.make(mod_names, exclude)