blob: 3b0f70991c079b529d8f1cabbb03defac71aa3ba [file] [log] [blame]
Skip Montanarod2681832002-04-30 16:25:37 +00001#!/usr/bin/env python
2
3# Released to the public domain by Skip Montanaro, 28 March 2002
4
5"""
6findsyms.py - try to identify undocumented symbols exported by modules
7
8Usage: findsyms.py librefdir
9
10For each lib*.tex file in the libref manual source directory, identify which
11module is documented, import the module if possible, then search the LaTeX
12source for the symbols global to that module. Report any that don't seem to
13be documented.
14
15Certain exceptions are made to the list of undocumented symbols:
16
17 * don't mention symbols in which all letters are upper case on the
18 assumption they are manifest constants
19
20 * don't mention symbols that are themselves modules
21
22 * don't mention symbols that match those exported by os, math, string,
23 types, or __builtin__ modules
24
25Finally, if a name is exported by the module but fails a getattr() lookup,
26that anomaly is reported.
27"""
28
29import __builtin__
30import getopt
31import glob
32import math
33import os
34import re
35import string
36import sys
37import types
38import warnings
39
40def usage():
41 print >> sys.stderr, """
42usage: %s dir
43where 'dir' is the Library Reference Manual source directory.
44""" % os.path.basename(sys.argv[0])
45
46def main():
47 try:
48 opts, args = getopt.getopt(sys.argv[1:], "")
49 except getopt.error:
50 usage()
51 return
52
53 if not args:
54 usage()
55 return
56
57 libdir = args[0]
58
59 warnings.filterwarnings("error")
60
61 pat = re.compile(r"\\declaremodule\s*{[^}]*}\s*{([^}]*)}")
62
63 missing = []
64 filelist = glob.glob(os.path.join(libdir, "lib*.tex"))
65 filelist.sort()
66 for f in filelist:
67 mod = f[3:-4]
68 if not mod: continue
69 data = open(f).read()
70 mods = re.findall(pat, data)
71 if not mods:
72 print "No module declarations found in", f
73 continue
74 for modname in mods:
75 # skip special modules
76 if modname.startswith("__"):
77 continue
78 try:
79 mod = __import__(modname)
80 except ImportError:
81 missing.append(modname)
82 continue
83 except DeprecationWarning:
84 print "Deprecated module:", modname
85 continue
86 if hasattr(mod, "__all__"):
87 all = mod.__all__
88 else:
89 all = [k for k in dir(mod) if k[0] != "_"]
90 mentioned = 0
91 all.sort()
92 for name in all:
93 if data.find(name) == -1:
94 # certain names are predominantly used for testing
95 if name in ("main","test","_test"):
96 continue
97 # is it some sort of manifest constant?
98 if name.upper() == name:
99 continue
100 try:
101 item = getattr(mod, name)
102 except AttributeError:
103 print " ", name, "exposed, but not an attribute"
104 continue
105 # don't care about modules that might be exposed
106 if type(item) == types.ModuleType:
107 continue
108 # check a few modules which tend to be import *'d
109 isglobal = 0
110 for m in (os, math, string, __builtin__, types):
111 if hasattr(m, name) and item == getattr(m, name):
112 isglobal = 1
113 break
114 if isglobal: continue
115 if not mentioned:
116 print "Not mentioned in", modname, "docs:"
117 mentioned = 1
118 print " ", name
119 if missing:
120 missing.sort()
121 print "Could not import:"
122 print " ", ", ".join(missing)
123
124if __name__ == "__main__":
125 try:
126 main()
127 except KeyboardInterrupt:
128 pass