root/NXLucene/trunk/doc/build_doc

Revision 35718, 15.4 kB (checked in by janguenot, 3 years ago)

exclude tests and fltests but document the nxlucene.Testing module

  • Property svn:executable set to *
Line 
1 #!/usr/bin/env python
2
3 #
4 # Taken from :
5 # http://cvs.sourceforge.net/viewcvs.py/cctools/publisher/build_doc?rev=1.3
6 #
7 # A bit refactored.
8 #
9 # $Id: $
10
11 # system
12 ### Twisted Preamble
13 # This makes sure that users don't have to set up their environment
14 # specially in order to run these programs from bin/.
15 import sys, os, string, shutil
16 #if string.find(os.path.abspath(sys.argv[0]), os.sep+'Twisted') != -1:
17 #    sys.path.insert(0, os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]
18 #), os.pardir, os.pardir)))
19 #sys.path.insert(0, os.curdir)
20 ### end of preamble
21
22 import os, sys
23 tmp_dir = '_epyrun_tmp' #only used for partial builds
24
25 # HACK: Don't import stuff that we don't like
26 # this is why we have to convert
27 def myimport(*args):
28     try:
29         return im(*args)
30     except:
31         mod = FakeModule(args[0], 4)
32         i = args[0].rfind('.')
33         if i != -1:
34             setattr(sys.modules[args[0][:i]], args[0][i+1:], mod)
35         return mod
36
37 class FakeModule:
38
39     def __init__(self, name, level):
40         self.__level = level
41         self.__name__ = name
42
43     def __repr__(self):
44         return '<Fake %s>' % self.__name__
45     __str__ = __repr__
46
47     def __nonzero__(self):
48         return 1
49
50     def __call__(self, *args, **kw):
51         pass #print 'Called:', args
52
53     def __getattr__(self, attr):
54         if self.__level == 0:
55             raise AttributeError
56         return FakeModule(self.__name__+'.'+attr, self.__level-1)
57
58     def __cmp__(self, other):
59         if not hasattr(other, '___name__'):
60             return -1
61         return cmp(self.__name__, other.__name__)
62
63 def fakeOut(modname):
64     modpath = modname.split('.')
65     prevmod = None
66     for m in range(len(modpath)):
67         mp = '.'.join(modpath[:m+1])
68         nm = FakeModule(mp, 4)
69         if prevmod:
70             setattr(prevmod, modpath[m], nm)
71         sys.modules[mp] = nm
72         prevmod = nm
73
74 #fakeOut("gnome.ui")
75 #fakeOut("pygtk")
76 #fakeOut("gtk")
77 #fakeOut("wxPython.wx")
78 #fakeOut('wx')
79 sys.modules["zope.interface._zope_interface_coptimizations"] = None
80
81 ## HACK: This is a nasty one! Replace TypeType with (TypeType,
82 ## InterfaceClass), and dir with something that makes Interfaces look like
83 ## classes so epydoc will try to document Interfaces.
84 from zope.interface.interface import InterfaceClass, Method, Attribute
85 import types
86 types.TypeType = (types.TypeType, InterfaceClass)
87 _marker = object()
88 def epydir(obj=_marker, dir=dir):
89     if obj is _marker:
90         return sys._getframe(1).f_locals.keys()
91     elif isinstance(obj, InterfaceClass):
92         return obj.names(all=True)
93     else:
94         return dir(obj)
95 import __builtin__
96 __builtin__.dir = epydir
97
98 # initial twisted
99 from twisted.python import reflect, util
100 #from twisted.internet import reactor
101 # epydoc
102 import epydoc
103 assert epydoc.__version__[0] == '2', "You need epydoc 2.x!"
104 from epydoc.cli import cli
105 from epydoc.html import HTMLFormatter, _write_if_nonempty
106 from epydoc import uid
107 import epydoc.html
108
109 # HACK: More zope.interface hackery -- zope.interface.interface.Methods are
110 # methods too!
111 is_method_orig = uid.ObjectUID.is_method
112 def is_method(self):
113     return is_method_orig(self) or isinstance(self._obj, Method)
114 uid.ObjectUID.is_method = is_method
115 is_routine_orig = uid.ObjectUID.is_routine
116 def is_routine(self):
117     return is_routine_orig(self) or isinstance(self._obj, Method)
118 uid.ObjectUID.is_routine = is_routine
119 _findname_orig = uid.ObjectUID._findname
120 def _findname(self):
121     if isinstance(self._obj, Method):
122         return '%s.%s' % (self.cls(), self._obj.__name__)
123     else:
124         return _findname_orig(self)
125 uid.ObjectUID._findname = _findname
126 cls_orig = uid.ObjectUID.cls
127 def cls(self):
128     if isinstance(self._obj, Method):
129         return uid.ObjectUID(self._obj.interface)
130     else:
131         return cls_orig(self)
132 uid.ObjectUID.cls = cls
133 module_orig = uid.ObjectUID.module
134 def module(self):
135     if isinstance(self._obj, Method):
136         return uid.ObjectUID(self._obj.interface).module()
137     else:
138         return module_orig(self)
139 uid.ObjectUID.module = module
140
141 make_uid_orig = uid.make_uid
142 def make_uid(obj, base_uid=None, shortname=None):
143     if isinstance(obj, Method):
144         key = (id(obj), id(obj.interface))
145         obj_uid = uid._object_uids.get(key)
146         if obj_uid is not None: return obj_uid
147         obj_uid = uid.ObjectUID(obj)
148         uid._object_uids[key] = obj_uid
149         return obj_uid
150     else:
151         return make_uid_orig(obj, base_uid, shortname)
152 uid.make_uid = make_uid
153
154 # HACK: Don't append -module and -class to the filenames, and generate
155 # redirecty-files for all methods.
156
157 class TwistedHTMLFormatter(HTMLFormatter):
158     def _uid_to_filename(self, uid):
159         # Enforce same restrictions as HTMLFormatter._uid_to_filename for sanity
160         # checking
161         assert uid.is_module() or uid.is_class(), 'Bad UID type: %r' % (uid,)
162         return uid.name() + '.html'
163        
164     def _uid_to_uri(self, uid):
165         if uid.is_module() or uid.is_class():
166             return uid.name() + '.html'
167
168         parent = uid.parent()
169         if parent is None:
170             return uid.name() + '.html'
171
172         return parent.name() + '.html#' + uid.shortname()
173
174     def _method_to_html(self, uid):
175         """
176         Dodgy redirect hack.
177         """
178         str = ('<html><head>\n'
179                '<meta http-equiv=refresh content="0; url=%s#%s">\n'
180                '</head></html>\n')
181         str = str % (self._uid_to_uri(uid.parent()), uid.shortname())
182         return str
183
184     def write(self, directory=None, progress_callback=None):
185         HTMLFormatter.write(self, directory, progress_callback)
186        
187         # Write method redirectors
188         self._write_method_redirects(directory)
189
190     def _write_method_redirects(self, directory):
191         import os.path
192         seen = {}
193         for uid, doc in self._docmap.data.iteritems():
194             if uid.is_method() or uid.is_function():
195                 if uid.name() in seen: continue
196                 seen[uid.name()] = 1
197                 filename = os.path.join(directory, uid.name() + '.html')
198                 #assert not os.path.exists(filename), filename
199                 s = self._method_to_html(uid)
200                 open(filename, 'w').write(s)
201
202     # fix barf on non-ASCII problem
203     def _write_func_details(self, public, private, container, functions,
204                         heading='Function Details'):
205
206         docmap = self._docmap
207         functions = [f for f in functions if docmap.has_key(f.target())]
208
209         cuid = container.uid()
210         if cuid.is_class():
211             # Filter out inherited methods (their details docs are
212             # listed under the class that defines them):
213             functions = [f for f in functions
214                          if f.target().cls() == cuid]
215
216             # Filter out methods that don't define or inherit docstrings;
217             # they are just listed in the summary table.
218             functions = [f for f in functions
219                          if docmap.documented_ancestor(f.target())]
220         else:
221             # Filter out functions that don't define docstrings; they
222             # are just listed in the summary table.
223             functions = [f for f in functions
224                          if docmap[f.target()].has_docstring()]
225
226         # If there are no functions left, then just return.
227         if len(functions) == 0: return
228        
229         # Divide the functions into groups
230         groups = container.by_group(functions)
231
232         # Write the table header
233         header = self._table_header(heading, 'details')+'</table>\n'
234         _write_if_nonempty(public, private, functions, header)
235
236         # Write an entry for each function.
237         for function in functions:
238             str = self._func_details_entry(function, container)
239             private.write("".join([n for n in str if ord(n) < 128]))
240             if function.target().is_public(): public.write(str)
241
242         # Write the table footer
243         _write_if_nonempty(public, private, functions, '<br />\n\n')
244
245     # when doing non-full builds we need to fake epydoc in to thinking that
246     # all twisted modules are being documented so that the html links
247     # to the modules that aren't being documented get generated correctly
248     def _documented(self, uid):
249         value = HTMLFormatter._documented(self, uid)
250         if not document_all:
251             if not value:
252                 try:
253                     if uid._name.startswith('twisted.'): #ha ha sucker
254                         return True
255                 except:
256                     pass
257         return value
258
259 epydoc.html.HTMLFormatter = TwistedHTMLFormatter
260
261 # HACK: Only document stuff that we _tell_ you to document, you stupid
262 # &#@&!#@
263
264 from epydoc import objdoc
265
266 # HACK: objdoc directly imports make_uid, so our monkeypatch to make_uid needs
267 # to happen here too:
268 objdoc.make_uid = make_uid
269
270 # HACK: add dummy im_func attr to Method to make epydoc happy
271 Method.im_func = property(lambda s: s)
272
273 # HACK: teach inspect.getargspec how to extract info from Methods
274 import inspect
275 getargspec_orig = inspect.getargspec
276 def getargspec(func):
277     if isinstance(func, Method):
278         spec = func.getSignatureInfo()
279         defaults = [spec['optional'][arg]
280                     for arg in spec['positional']
281                     if arg in spec['optional']]
282         return (spec['positional'], spec['varargs'], spec['kwargs'], defaults)
283     else:
284         return getargspec_orig(func)
285 inspect.getargspec = getargspec
286
287 # HACK: Make FuncDoc DTRT with Methods
288 _init_signature_orig = objdoc.FuncDoc._init_signature
289 # This one is for epydoc CVS
290 def _init_signature(self, func):
291     if isinstance(func, Method):
292         docstring = objdoc._getdoc(func)
293         self._init_signature_from_argspec(*inspect.getargspec(func))
294         return docstring
295     else:
296         return _init_signature_orig(self, func)
297 objdoc.FuncDoc._init_signature = _init_signature
298
299 # This one is for epydoc 2.1
300 _init_builtin_signature_orig = objdoc.FuncDoc._init_builtin_signature
301 def _init_builtin_signature(self, func):
302     if isinstance(func, Method):
303         _init_signature_orig(self, func)
304         return False
305     else:
306         return _init_builtin_signature_orig(self, func)
307 objdoc.FuncDoc._init_builtin_signature = _init_builtin_signature
308
309
310 ### NRY 24 Jun 2005
311 # make attribute introspection work
312 _lookup_class_field_orig = objdoc._lookup_class_field
313
314 def _lookup_class_field(cls, field, base_order=None):
315     result = _lookup_class_field_orig(cls, field, base_order)
316
317     if result[0] ==  '<Not Accessible>':
318         if isinstance(cls, InterfaceClass):
319             target = cls[field]
320             repr = result[0]
321            
322             if isinstance(target, (Attribute, Method)):
323                 repr = target.getDoc()
324                
325             result = (repr, result[1])
326
327     return result
328
329     pass
330 objdoc._lookup_class_field = _lookup_class_field
331
332
333 # HACK: Another "only doc what we tell you". We don't want epydoc to
334 # automatically recurse into subdirectories: "twisted"'s presence was
335 # causing "twisted/test" to be docced, even thought we explicitly
336 # didn't put any twisted/test in our modnames.
337
338 from epydoc import imports
339 orig_find_modules = imports.find_modules
340
341 import re
342
343 def find_modules(dirname):
344     if not os.path.isdir(dirname): return []
345     found_init = 0
346     modules = {}
347     dirs = []
348
349     # Search for directories & modules, and check for __init__.py.
350     # Don't include duplicates (like foo.py and foo.pyc), and give
351     # precedance to the .py files.
352     for file in os.listdir(dirname):
353         filepath = os.path.join(dirname, file)
354         if os.path.isdir(filepath): dirs.append(filepath)
355         elif not re.match(r'\w+.py.?', file):
356             continue # Ignore things like ".#foo.py" or "a-b.py"
357         elif file[-3:] == '.py':
358             modules[file] = os.path.join(dirname, file)
359             if file == '__init__.py': found_init = 1
360         elif file[-4:-1] == '.py':
361             modules.setdefault(file[:-1], file)
362             if file[:-1] == '__init__.py': found_init = 1
363     modules = modules.values()
364
365     # If there was no __init__.py, then this isn't a package
366     # directory; return nothing.
367     if not found_init: return []
368
369     # Recurse to the child directories.
370     # **twisted** here's the change: commented next line out
371     for d in dirs:
372         if 'tests' in d or 'fltests' in d:
373             continue
374         modules += find_modules(d)
375     return modules
376
377
378 imports.find_modules = find_modules
379
380
381
382 # Now, set up the list of modules for epydoc to document
383 modnames = []
384 def addMod(arg, path, files):
385     if 'test' in files:
386         files.remove('test')
387     if 'topfiles' in files:
388         files.remove('topfiles')
389     for fn in files:
390         file = os.path.join(path, fn).replace('%s__init__'%os.sep, '')
391         if file[-3:] == '.py':
392             modName = file[:-3].replace(os.sep,'.')
393             try:
394                 #print 'pre-loading', modName
395                 reflect.namedModule(modName)
396             except ImportError:
397                 print 'import error:', modName
398             except:
399                 print 'other error:', modName
400             else:
401                 modnames.append(modName)
402
403 document_all = True # are we doing a full build?
404 names = ['zope',] #default, may be overriden below
405
406 #get list of modules/pkgs on cmd-line
407 try:
408     i = sys.argv.index("--modules")
409 except:
410     pass
411 else:
412     names = sys.argv[i+1:]
413     document_all = False
414     sys.argv[i:] = []
415     #sanity check on names
416     #for i in range(len(names)):
417     #    try:
418     #        j = names[i].rindex('twisted/')
419     #    except:
420     #        raise SystemExit, 'You can only specify twisted modules or packages'
421     #    else:
422     #        #strip off any leading directories before the 'twisted/'
423     #         #dir. this makes it easy to specify full paths, such as
424     #         #from TwistedEmacs
425     #         names[i] = names[i][j:]
426
427     old_out_dir = "html"
428     #if -o was specified, we need to change it to point to a tmp dir
429     #otherwise add our own -o option
430     try:
431         i = sys.argv.index('-o')
432         old_out_dir = sys.argv[i+1]
433         try:
434             os.mkdir(tmp_dir)
435         except OSError:
436             pass
437         sys.argv[i+1] = tmp_dir
438     except ValueError:
439         sys.argv[1:1] = ['-o', tmp_dir]
440
441 osrv = sys.argv
442 sys.argv=["IGNORE"]
443 im = __import__
444 __builtins__.__import__ = myimport
445
446 for name in names:
447     if name.endswith(".py"):
448         # turn it in to a python module name
449         name = name[:-3].replace(os.sep, ".")
450         try:
451             reflect.namedModule(name)
452         except ImportError:
453             print 'import error:', name
454         except Exception, e:
455             print 'other error:', name, e
456         else:
457             modnames.append(name)
458     else: #assume it's a dir
459         os.path.walk(name, addMod, None)
460
461 __builtins__.__import__ = im
462 sys.argv = osrv
463
464
465
466
467 if 'twisted.test' in modnames:
468     modnames.remove('twisted.test')
469
470 ##if 'twisted' in modnames:
471 ##    modnames.remove('twisted')
472
473 sys.argv.extend(modnames)
474
475 # Make it easy to profile epyrun
476 if 0:
477     import profile
478     profile.run('cli()', 'epyrun.prof')
479 else:
480     cli()
481
482 # used when doing partial builds to move the new files
483 # out of the tmp dir and in to the real output dir.
484 # only does "twisted." files since the others (index.html and such)
485 # won't be right when not doing full builds.
486 def moveFilesOut(arg, dirname, fnames):
487     for fn in fnames:
488         if fn.startswith('twisted.'):
489             shutil.move('%s%s%s' % (tmp_dir, os.sep, fn), old_out_dir)
490        
491 if not document_all:
492     print "Updating files in %s" % old_out_dir
493     #move the right html files in to place
494     os.path.walk(tmp_dir, moveFilesOut, None)
495     #clean up
496     shutil.rmtree(tmp_dir)
497
498 print 'Done!'
Note: See TracBrowser for help on using the browser.