root / PyCon07 / material / pycommunity_documented / package.py

Revision 57:efd3c5bd5313, 8.8 kB (checked in by Tarek Ziad?? <tarek@…>, 23 months ago)

more on recipes

Line 
1#!/usr/bin/python
2# -*- coding: UTF-8 -*-
3#
4# Copyright (c) 2006 Tarek Ziadé <tarek@ziade.org>
5#
6# This program is free software; you can redistribute it and/or
7# modify it under the terms of the GNU General Public License
8# as published by the Free Software Foundation; either version 2
9# of the License, or (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program; if not, write to the Free Software
18# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19# $Id: $
20""" package doc builder
21"""
22import os
23import logging
24
25from Cheetah.Template import Template
26try:
27    from epydoc.cli import write_html
28    from epydoc.docbuilder import build_doc_index
29    epydoc = True
30except ImportError:
31    epydoc = False
32
33try:
34    from cheesecake.cheesecake_index import Cheesecake
35    cheese = True
36except ImportError:
37    cheese = False
38
39from generator import registerTask
40from resttask import TaskView
41from utils import extractHtmlContent
42from utils import rest2Web
43
44class PackageIndexView(object):
45    """renders the package index"""
46    def __init__(self, templatefile, folder, options):
47        indexdoc, otherdocs = self._computeDocList(folder)
48
49        self._template = Template(open(templatefile).read(),
50                                  searchList=[{'docs': otherdocs,
51                                               'main': indexdoc[1],
52                                               'title': indexdoc[0],
53                                               'options': options}])
54
55    def _computeDocList(self, folder):
56        """gathers a list of all docs
57
58        and a reST render of README.txt if founded
59        """
60        docs = []
61        indexdoc = None, None
62        for element in os.listdir(folder):
63            fullpath = os.path.join(folder, element)
64            fullpath = os.path.realpath(fullpath)
65            if os.path.isfile(fullpath):
66                if element.lower() == 'index.html':
67                    # we don't want it listed
68                    pass
69                elif element.lower() == 'readme.html':
70                    # let's grab its content, to inject it in
71                    # the index
72                    indexdoc = extractHtmlContent(fullpath)
73                else:
74                    title, body = extractHtmlContent(fullpath)
75                    webpath = './%s' % element
76                    docs.append((title, webpath))
77        return indexdoc, docs
78
79    def render(self):
80        """renders the html"""
81        return str(self._template)
82    __call__ = render
83
84class PackagesIndexView(object):
85    """renders the global index"""
86    def __init__(self, templatefile, folder, options):
87        packages = self._computePackageList(folder)
88        title, content = rest2Web(options['packages'])
89        self._template = Template(open(templatefile).read(),
90                                  searchList=[{'packages': packages,
91                                               'options': options,
92                                               'title': title,
93                                               'content': content}])
94
95    def _computePackageList(self, folder):
96        """gathers a list of all subfolders"""
97        dirs = []
98        for element in os.listdir(folder):
99            fullpath = os.path.join(folder, element)
100            if os.path.isdir(fullpath):
101                webpath = './%s' % element
102                dirs.append((element, webpath))
103        return dirs
104
105    def render(self):
106        """renders the html"""
107        return str(self._template)
108    __call__ = render
109
110class PackageTask(object):
111    """creates the documentation for packages"""
112
113    def _writeFile(self, name, content):
114        """write a file"""
115        f = open(name, 'w')
116        logging.info('writing %s' % name)
117        try:
118            f.write(content)
119        finally:
120            f.close()
121
122    def _getName(self):
123        return 'package'
124   
125    def _makeDirectory(self, path):
126        """check that the given directory exists"""
127        if os.path.exists(path):
128            return
129        os.makedirs(path)
130
131    def _getFiles(self, folder, extension):
132        """lists all files, given an extension"""
133        ffiles = []
134        for root, dirs, files in os.walk(folder):
135            for file_ in files:
136                if not file_.endswith('.%s' % extension):
137                    continue
138                file_ = os.path.join(root, file_)
139                ffiles.append(os.path.realpath(file_))
140        return ffiles
141
142    def _listSources(self, folder):
143        """lists all python files, given a folder, recursive"""
144        return self._getFiles(folder, 'py')
145
146    def _getRestFiles(self, folder):
147        """lists all rest file, given a folder recursive"""
148        return self._getFiles(folder, 'txt')
149
150    def _run(self, configuration):
151        """generates packages"""
152        targets = configuration.targets.values()
153        packages = configuration.packages.values()
154        self._rest_template = configuration.templates['packagedoc']
155        self._stats_template = configuration.templates['packagestats']
156        self._index_template = configuration.templates['packageindex']
157        self._global_index_template = configuration.templates['packagesindex']
158        self._glossary_file = configuration.glossary
159        self._options = configuration.options
160
161        for target in targets:
162            root = os.path.join(target, 'packages')
163            root = os.path.realpath(root)
164
165            # making the top directory if needed
166            self._makeDirectory(root)
167
168            for package in packages:
169
170                basename = os.path.split(package)[-1]
171                package_root = os.path.join(root, basename)
172
173                # making the directory if needed
174                self._makeDirectory(package_root)
175
176                # collecting the reST files and generating them
177                restfiles = self._getRestFiles(package)
178                self._makeRestFiles(restfiles, package_root)
179 
180                # generating APIs with epydoc
181                self._makeAPIs(package, package_root)
182
183                # generating stats page
184                self._makeStats(package, package_root)
185               
186                # making the package index
187                self._makeIndex(package_root)
188
189            # making the packages index
190            self._makeGlobalIndex(root)
191
192    def _getHTMLName(self, filename):
193        """compute html file"""
194        base = os.path.split(filename)[-1].split('.')[0]
195        return '%s.html' % base
196
197    def _makeRestFiles(self, files, folder):
198        """generates rest files into the given folder"""
199        template = self._rest_template
200        glossary = self._glossary_file
201
202        for file_ in files:
203            view = TaskView(template, file_, glossary)
204            filename = os.path.join(folder, self._getHTMLName(file_))
205            self._writeFile(filename, view()[1])
206
207    def _makeAPIs(self, package, folder):
208        """generates epydoc docs"""
209        if not epydoc:
210            return
211        class EpyDocOptions(object):
212            def __init__(self, target):
213                self.target = target
214                self.verbose = False
215
216        target = os.path.join(folder, 'epydoc')
217        options = EpyDocOptions(target)
218        names = self._listSources(package)
219        try:
220            docindex = build_doc_index(names, True, True,
221                                       add_submodules=True)
222        except (AttributeError, ValueError):
223            # a zope package ?
224            return 
225        if docindex is None:
226            # nothing to build
227            return
228        write_html(docindex, options)
229
230    def _makeStats(self, package, folder):
231        """generates stat page
232
233        Using:
234            - cheesecake
235            - trace2html
236        """
237        return
238        if cheese:
239            # cheesecacke wants an egg or a tarball..
240            indexer = Cheesecake(path=path)
241            indexer.compute_cheesecake_index()
242            indexer.cleanup()
243
244    def _makeIndex(self, folder):
245        """generates package index page
246
247        wich contains a list of documents and
248        display README.txt's content in the main view
249        """
250        template = self._index_template
251        view = PackageIndexView(template, folder, self._options)
252        filename = os.path.join(folder, 'index.html')
253        self._writeFile(filename, view())
254
255    def _makeGlobalIndex(self, folder):
256        """generates global package index page"""
257        template = self._global_index_template
258        view = PackagesIndexView(template, folder, self._options)
259        filename = os.path.join(folder, 'index.html')
260        self._writeFile(filename, view())
261
262registerTask(PackageTask)
Note: See TracBrowser for help on using the browser.