#! /usr/bin/env python # -*- Python -*- # # This script can be used to identify undocumented modules in the Python # standard library. Use it like this: # # .../Doc/tools/listmodules --ignore-from .../Doc/paper-/modlib.idx """%(program)s - list modules in the Python standard library -a, --annotate Annotate the module names with the subdirectory they live in -c, --categorize Group the modules by subdirectory -i , --ignore-from Ignore the modules listed in . may contain a list of module names or a module index file as produced when formatting the Python documentation (.idx flavor). If neither -a nor -c are given, the modules are listed in alphabetical order. Note that -a and -c are mutually exclusive. Limitation: Modules loadable as shared objects are not listed. """ __version__ = '$Revision$' import getopt import os import re import string import sys REMOVE_DIRS = ["dos-8x3", "lib-old", "lib-stdwin", "test"] def main(): args = sys.argv[1:] annotate = 0 builtin = 0 categorize = 0 ignore_dict = {} ignore = ignore_dict.has_key try: opts, args = getopt.getopt( args, "abchi:", ["annotate", "built-in", "categorize", "help", "ignore-from="]) except getopt.error, msg: sys.stdout = sys.stderr print msg print usage() sys.exit(2) for opt, arg in opts: if opt in ("-a", "--annotate"): annotate = 1 elif opt in ("-b", "--built-in"): builtin = 1 elif opt in ("-c", "--categorize"): categorize = 1 elif opt in ("-h", "--help"): usage() sys.exit() elif opt in ("-i", "--ignore-from"): data = open(arg).read() if data[:1] == "\\": ignore_from_idx(data, ignore_dict) else: ignore_from_filelist(data, ignore_dict) if args or (annotate and categorize): usage() sys.exit(2) # # Populate the database: # srcdir = os.path.normpath(os.path.join( os.path.dirname(sys.argv[0]), os.pardir, os.pardir)) os.chdir(srcdir) fp = os.popen("find Lib -name \*.py -print", "r") modules_by_name = {} modules_by_dir = {} if builtin: l = [] modules_by_dir[""] = l for name in sys.builtin_module_names: if not ignore(name): modules_by_name[name] = "" l.append(name) rx = re.compile("Lib/plat-[a-z0-9]*/", re.IGNORECASE) while 1: line = fp.readline() if not line: break m = rx.match(line) if m: line = "Lib/plat-*/" + line[m.end():] line = line[4:-4] # strip off 'Lib/' and '.py\n' dir, name = os.path.split(line) dir = dir or "" if ignore(name): continue if dir not in REMOVE_DIRS: modules_by_name[name] = dir l = modules_by_dir.get(dir, []) modules_by_dir[dir] = l if name not in l: l.append(name) # # Dump the results: # if annotate: modules = modules_by_name.items() modules.sort() width = max(map(len, modules_by_name.keys())) format = "%%-%ds %%s" % width for name, dir in modules: if dir and dir[0] != "<": print format % (name, dir) else: print name elif categorize: modules = modules_by_dir.items() modules.sort() width = max(map(len, modules_by_dir.keys())) format = "%%-%ds %%s" % width for dir, names in modules: names.sort() print format % (dir, names[0]) for name in names[1:]: print format % ('', name) print else: modules = modules_by_name.keys() modules.sort() print string.join(modules, "\n") def ignore_from_filelist(data, ignore_dict): for name in string.split(data): ignore_dict[name] = name def ignore_from_idx(data, ignore_dict): data = string.replace(data, r"\hackscore {}", "_") rx = re.compile(r"\indexentry {([^@]*)@") for line in string.split(data, "\n"): m = rx.match(line) if m: name = m.group(1) ignore_dict[name] = name def usage(): vars = {} vars["program"] = os.path.basename(sys.argv[0]) print __doc__ % vars if __name__ == "__main__": main()