blob: 03e7b5dc0843b96c5fd14b06294da519e74efd12 [file] [log] [blame]
Fred Drakeb6cf9a41999-02-23 23:07:48 +00001#! /usr/bin/env python
2# -*- Python -*-
3#
4# This script can be used to identify undocumented modules in the Python
5# standard library. Use it like this:
6#
7# .../Doc/tools/listmodules --ignore-from .../Doc/paper-<paper>/modlib.idx
8
9"""%(program)s - list modules in the Python standard library
10
Fred Drake2ed27d32000-11-17 19:05:12 +000011-a, --annotate Annotate the module names with the subdirectory they
12 live in
Fred Drakeb6cf9a41999-02-23 23:07:48 +000013-c, --categorize Group the modules by subdirectory
14-i <file>,
Fred Drakeb6cf9a41999-02-23 23:07:48 +000015
Fred Drake2ed27d32000-11-17 19:05:12 +000016--ignore-from <file> Ignore the modules listed in <file>. <file> may
17 contain a list of module names or a module index file
18 as produced when formatting the Python documentation
19 (.idx or .html flavor).
20
21If neither -a nor -c are given, the modules are listed in alphabetical
22order.
Fred Drakeb6cf9a41999-02-23 23:07:48 +000023
24Note that -a and -c are mutually exclusive.
25
Fred Drake2ed27d32000-11-17 19:05:12 +000026Limitation: Modules loadable as shared objects may not be listed,
27though this script attempts to locate such modules.
28
Fred Drakeb6cf9a41999-02-23 23:07:48 +000029"""
30
31__version__ = '$Revision$'
32
33import getopt
Fred Drake924b42d1999-06-17 18:49:18 +000034import glob
Fred Drakeb6cf9a41999-02-23 23:07:48 +000035import os
36import re
37import string
38import sys
39
40
Fred Drake2ed27d32000-11-17 19:05:12 +000041REMOVE_DIRS = ["dos-8x3", "encodings", "distutils",
42 "lib-old", "lib-stdwin", "test"]
Fred Drakeb6cf9a41999-02-23 23:07:48 +000043
44
45def main():
46 args = sys.argv[1:]
47 annotate = 0
48 builtin = 0
49 categorize = 0
50 ignore_dict = {}
51 ignore = ignore_dict.has_key
52 try:
53 opts, args = getopt.getopt(
54 args, "abchi:",
55 ["annotate", "built-in", "categorize", "help", "ignore-from="])
56 except getopt.error, msg:
57 sys.stdout = sys.stderr
58 print msg
59 print
60 usage()
61 sys.exit(2)
62 for opt, arg in opts:
63 if opt in ("-a", "--annotate"):
64 annotate = 1
65 elif opt in ("-b", "--built-in"):
66 builtin = 1
67 elif opt in ("-c", "--categorize"):
68 categorize = 1
69 elif opt in ("-h", "--help"):
70 usage()
71 sys.exit()
72 elif opt in ("-i", "--ignore-from"):
73 data = open(arg).read()
74 if data[:1] == "\\":
75 ignore_from_idx(data, ignore_dict)
76 else:
Fred Drake093c97a1999-02-24 18:39:47 +000077 ignore_from_modulelist(data, ignore_dict)
Fred Drakeb6cf9a41999-02-23 23:07:48 +000078 if args or (annotate and categorize):
79 usage()
80 sys.exit(2)
81 #
82 # Populate the database:
83 #
84 srcdir = os.path.normpath(os.path.join(
85 os.path.dirname(sys.argv[0]), os.pardir, os.pardir))
86 os.chdir(srcdir)
Fred Drakeb6cf9a41999-02-23 23:07:48 +000087 modules_by_name = {}
88 modules_by_dir = {}
89 if builtin:
90 l = []
91 modules_by_dir["<builtin>"] = l
92 for name in sys.builtin_module_names:
93 if not ignore(name):
94 modules_by_name[name] = "<built-in>"
95 l.append(name)
Fred Drake2ed27d32000-11-17 19:05:12 +000096 rx = re.compile("Lib/plat-[a-zA-Z0-9]*/")
Fred Drake924b42d1999-06-17 18:49:18 +000097 fp = os.popen("find Lib -name \*.py -print", "r")
Fred Drakeb6cf9a41999-02-23 23:07:48 +000098 while 1:
99 line = fp.readline()
100 if not line:
101 break
102 m = rx.match(line)
103 if m:
104 line = "Lib/plat-*/" + line[m.end():]
105 line = line[4:-4] # strip off 'Lib/' and '.py\n'
106 dir, name = os.path.split(line)
107 dir = dir or "<standard>"
108 if ignore(name):
109 continue
110 if dir not in REMOVE_DIRS:
111 modules_by_name[name] = dir
112 l = modules_by_dir.get(dir, [])
113 modules_by_dir[dir] = l
114 if name not in l:
115 l.append(name)
Fred Drake924b42d1999-06-17 18:49:18 +0000116 # load up extension modules:
117 pwd = os.getcwd()
118 try:
119 os.chdir("Modules")
120 dir = "<extension>"
121 for line in glob.glob("*module.c"):
122 name = line[:-8]
123 if ignore(name) or modules_by_name.has_key(name) or name == "xx":
124 continue
125 modules_by_name[name] = dir
126 l = modules_by_dir.get(dir, [])
127 modules_by_dir[dir] = l
128 if name not in l:
129 l.append(name)
130 finally:
131 os.chdir(pwd)
Fred Drakeb6cf9a41999-02-23 23:07:48 +0000132 #
133 # Dump the results:
134 #
135 if annotate:
136 modules = modules_by_name.items()
137 modules.sort()
138 width = max(map(len, modules_by_name.keys()))
139 format = "%%-%ds %%s" % width
140 for name, dir in modules:
141 if dir and dir[0] != "<":
142 print format % (name, dir)
143 else:
144 print name
145 elif categorize:
146 modules = modules_by_dir.items()
147 modules.sort()
148 width = max(map(len, modules_by_dir.keys()))
149 format = "%%-%ds %%s" % width
150 for dir, names in modules:
151 names.sort()
152 print format % (dir, names[0])
153 for name in names[1:]:
154 print format % ('', name)
155 print
156 else:
157 modules = modules_by_name.keys()
158 modules.sort()
159 print string.join(modules, "\n")
160
161
Fred Drake093c97a1999-02-24 18:39:47 +0000162def ignore_from_modulelist(data, ignore_dict):
Fred Drakeb6cf9a41999-02-23 23:07:48 +0000163 for name in string.split(data):
164 ignore_dict[name] = name
165
166def ignore_from_idx(data, ignore_dict):
167 data = string.replace(data, r"\hackscore {}", "_")
Fred Drake093c97a1999-02-24 18:39:47 +0000168 rx = re.compile(r"\\indexentry\s*{([^@]*)@")
Fred Drakeb6cf9a41999-02-23 23:07:48 +0000169 for line in string.split(data, "\n"):
170 m = rx.match(line)
171 if m:
172 name = m.group(1)
173 ignore_dict[name] = name
174
175
176def usage():
177 vars = {}
178 vars["program"] = os.path.basename(sys.argv[0])
179 print __doc__ % vars
180
181
182if __name__ == "__main__":
183 main()