summaryrefslogtreecommitdiffstats
path: root/Lib/pydoc.py
diff options
context:
space:
mode:
authorThomas Wouters <thomas@python.org>2006-04-21 10:40:58 (GMT)
committerThomas Wouters <thomas@python.org>2006-04-21 10:40:58 (GMT)
commit49fd7fa4431da299196d74087df4a04f99f9c46f (patch)
tree35ace5fe78d3d52c7a9ab356ab9f6dbf8d4b71f4 /Lib/pydoc.py
parent9ada3d6e29d5165dadacbe6be07bcd35cfbef59d (diff)
downloadcpython-49fd7fa4431da299196d74087df4a04f99f9c46f.zip
cpython-49fd7fa4431da299196d74087df4a04f99f9c46f.tar.gz
cpython-49fd7fa4431da299196d74087df4a04f99f9c46f.tar.bz2
Merge p3yk branch with the trunk up to revision 45595. This breaks a fair
number of tests, all because of the codecs/_multibytecodecs issue described here (it's not a Py3K issue, just something Py3K discovers): http://mail.python.org/pipermail/python-dev/2006-April/064051.html Hye-Shik Chang promised to look for a fix, so no need to fix it here. The tests that are expected to break are: test_codecencodings_cn test_codecencodings_hk test_codecencodings_jp test_codecencodings_kr test_codecencodings_tw test_codecs test_multibytecodec This merge fixes an actual test failure (test_weakref) in this branch, though, so I believe merging is the right thing to do anyway.
Diffstat (limited to 'Lib/pydoc.py')
-rwxr-xr-xLib/pydoc.py182
1 files changed, 73 insertions, 109 deletions
diff --git a/Lib/pydoc.py b/Lib/pydoc.py
index b6afc7f..cf38630 100755
--- a/Lib/pydoc.py
+++ b/Lib/pydoc.py
@@ -52,10 +52,16 @@ Richard Chamberlain, for the first implementation of textdoc.
# the current directory is changed with os.chdir(), an incorrect
# path will be displayed.
-import sys, imp, os, re, types, inspect, __builtin__
+import sys, imp, os, re, types, inspect, __builtin__, pkgutil
from repr import Repr
from string import expandtabs, find, join, lower, split, strip, rfind, rstrip
-from collections import deque
+try:
+ from collections import deque
+except ImportError:
+ # Python 2.3 compatibility
+ class deque(list):
+ def popleft(self):
+ return self.pop(0)
# --------------------------------------------------------- common routines
@@ -182,6 +188,23 @@ def ispackage(path):
return True
return False
+def source_synopsis(file):
+ line = file.readline()
+ while line[:1] == '#' or not strip(line):
+ line = file.readline()
+ if not line: break
+ line = strip(line)
+ if line[:4] == 'r"""': line = line[1:]
+ if line[:3] == '"""':
+ line = line[3:]
+ if line[-1:] == '\\': line = line[:-1]
+ while not strip(line):
+ line = file.readline()
+ if not line: break
+ result = strip(split(line, '"""')[0])
+ else: result = None
+ return result
+
def synopsis(filename, cache={}):
"""Get the one-line summary out of a module file."""
mtime = os.stat(filename).st_mtime
@@ -196,24 +219,11 @@ def synopsis(filename, cache={}):
if info and 'b' in info[2]: # binary modules have to be imported
try: module = imp.load_module('__temp__', file, filename, info[1:])
except: return None
- result = split(module.__doc__ or '', '\n')[0]
+ result = (module.__doc__ or '').splitlines()[0]
del sys.modules['__temp__']
else: # text modules can be directly examined
- line = file.readline()
- while line[:1] == '#' or not strip(line):
- line = file.readline()
- if not line: break
- line = strip(line)
- if line[:4] == 'r"""': line = line[1:]
- if line[:3] == '"""':
- line = line[3:]
- if line[-1:] == '\\': line = line[:-1]
- while not strip(line):
- line = file.readline()
- if not line: break
- result = strip(split(line, '"""')[0])
- else: result = None
- file.close()
+ result = source_synopsis(file)
+ file.close()
cache[filename] = (mtime, result)
return result
@@ -643,16 +653,8 @@ class HTMLDoc(Doc):
if hasattr(object, '__path__'):
modpkgs = []
- modnames = []
- for file in os.listdir(object.__path__[0]):
- path = os.path.join(object.__path__[0], file)
- modname = inspect.getmodulename(file)
- if modname != '__init__':
- if modname and modname not in modnames:
- modpkgs.append((modname, name, 0, 0))
- modnames.append(modname)
- elif ispackage(path):
- modpkgs.append((file, name, 1, 0))
+ for importer, modname, ispkg in pkgutil.iter_modules(object.__path__):
+ modpkgs.append((modname, name, ispkg, 0))
modpkgs.sort()
contents = self.multicolumn(modpkgs, self.modpkglink)
result = result + self.bigsection(
@@ -796,7 +798,10 @@ class HTMLDoc(Doc):
tag += ':<br>\n'
# Sort attrs by name.
- attrs.sort(key=lambda t: t[0])
+ try:
+ attrs.sort(key=lambda t: t[0])
+ except TypeError:
+ attrs.sort(lambda t1, t2: cmp(t1[0], t2[0])) # 2.3 compat
# Pump out the attrs, segregated by kind.
attrs = spill('Methods %s' % tag, attrs,
@@ -914,25 +919,9 @@ class HTMLDoc(Doc):
"""Generate an HTML index for a directory of modules."""
modpkgs = []
if shadowed is None: shadowed = {}
- seen = {}
- files = os.listdir(dir)
-
- def found(name, ispackage,
- modpkgs=modpkgs, shadowed=shadowed, seen=seen):
- if name not in seen:
- modpkgs.append((name, '', ispackage, name in shadowed))
- seen[name] = 1
- shadowed[name] = 1
-
- # Package spam/__init__.py takes precedence over module spam.py.
- for file in files:
- path = os.path.join(dir, file)
- if ispackage(path): found(file, 1)
- for file in files:
- path = os.path.join(dir, file)
- if os.path.isfile(path):
- modname = inspect.getmodulename(file)
- if modname: found(modname, 0)
+ for importer, name, ispkg in pkgutil.iter_modules([dir]):
+ modpkgs.append((name, '', ispkg, name in shadowed))
+ shadowed[name] = 1
modpkgs.sort()
contents = self.multicolumn(modpkgs, self.modpkglink)
@@ -1059,14 +1048,12 @@ class TextDoc(Doc):
if hasattr(object, '__path__'):
modpkgs = []
- for file in os.listdir(object.__path__[0]):
- path = os.path.join(object.__path__[0], file)
- modname = inspect.getmodulename(file)
- if modname != '__init__':
- if modname and modname not in modpkgs:
- modpkgs.append(modname)
- elif ispackage(path):
- modpkgs.append(file + ' (package)')
+ for importer, modname, ispkg in pkgutil.iter_modules(object.__path__):
+ if ispkg:
+ modpkgs.append(modname + ' (package)')
+ else:
+ modpkgs.append(modname)
+
modpkgs.sort()
result = result + self.section(
'PACKAGE CONTENTS', join(modpkgs, '\n'))
@@ -1490,20 +1477,9 @@ def writedoc(thing, forceload=0):
def writedocs(dir, pkgpath='', done=None):
"""Write out HTML documentation for all modules in a directory tree."""
if done is None: done = {}
- for file in os.listdir(dir):
- path = os.path.join(dir, file)
- if ispackage(path):
- writedocs(path, pkgpath + file + '.', done)
- elif os.path.isfile(path):
- modname = inspect.getmodulename(path)
- if modname:
- if modname == '__init__':
- modname = pkgpath[:-1] # remove trailing period
- else:
- modname = pkgpath + modname
- if modname not in done:
- done[modname] = 1
- writedoc(modname)
+ for importer, modname, ispkg in pkgutil.walk_packages([dir], pkgpath):
+ writedoc(modname)
+ return
def raw_input(prompt):
sys.stdout.write(prompt)
@@ -1835,30 +1811,9 @@ class Scanner:
self.state.append((child, self.children(child)))
return child
-class ModuleScanner(Scanner):
- """An interruptible scanner that searches module synopses."""
- def __init__(self):
- roots = map(lambda dir: (dir, ''), pathdirs())
- Scanner.__init__(self, roots, self.submodules, self.isnewpackage)
- self.inodes = map(lambda (dir, pkg): os.stat(dir).st_ino, roots)
-
- def submodules(self, (dir, package)):
- children = []
- for file in os.listdir(dir):
- path = os.path.join(dir, file)
- if ispackage(path):
- children.append((path, package + (package and '.') + file))
- else:
- children.append((path, package))
- children.sort() # so that spam.py comes before spam.pyc or spam.pyo
- return children
- def isnewpackage(self, (dir, package)):
- inode = os.path.exists(dir) and os.stat(dir).st_ino
- if not (os.path.islink(dir) and inode in self.inodes):
- self.inodes.append(inode) # detect circular symbolic links
- return ispackage(dir)
- return False
+class ModuleScanner:
+ """An interruptible scanner that searches module synopses."""
def run(self, callback, key=None, completer=None):
if key: key = lower(key)
@@ -1875,22 +1830,31 @@ class ModuleScanner(Scanner):
if find(lower(modname + ' - ' + desc), key) >= 0:
callback(None, modname, desc)
- while not self.quit:
- node = self.next()
- if not node: break
- path, package = node
- modname = inspect.getmodulename(path)
- if os.path.isfile(path) and modname:
- modname = package + (package and '.') + modname
- if not modname in seen:
- seen[modname] = 1 # if we see spam.py, skip spam.pyc
- if key is None:
- callback(path, modname, '')
+ for importer, modname, ispkg in pkgutil.walk_packages():
+ if self.quit:
+ break
+ if key is None:
+ callback(None, modname, '')
+ else:
+ loader = importer.find_module(modname)
+ if hasattr(loader,'get_source'):
+ import StringIO
+ desc = source_synopsis(
+ StringIO.StringIO(loader.get_source(modname))
+ ) or ''
+ if hasattr(loader,'get_filename'):
+ path = loader.get_filename(modname)
else:
- desc = synopsis(path) or ''
- if find(lower(modname + ' - ' + desc), key) >= 0:
- callback(path, modname, desc)
- if completer: completer()
+ path = None
+ else:
+ module = loader.load_module(modname)
+ desc = (module.__doc__ or '').splitlines()[0]
+ path = getattr(module,'__file__',None)
+ if find(lower(modname + ' - ' + desc), key) >= 0:
+ callback(path, modname, desc)
+
+ if completer:
+ completer()
def apropos(key):
"""Print all the one-line module summaries that contain a substring."""
@@ -1955,7 +1919,7 @@ def serve(port, callback=None, completer=None):
'Built-in Modules', '#ffffff', '#ee77aa', contents)]
seen = {}
- for dir in pathdirs():
+ for dir in sys.path:
indices.append(html.index(dir, seen))
contents = heading + join(indices) + '''<p align=right>
<font color="#909090" face="helvetica, arial"><strong>