import sys
import imp
-import tokenize # Python tokenizer
-from token import NAME, DEDENT, NEWLINE, OP
+import tokenize
+from token import NAME, DEDENT, OP
from operator import itemgetter
__all__ = ["readmodule", "readmodule_ex", "Class", "Function"]
self.file = file
self.lineno = lineno
-def readmodule(module, path=[]):
+def readmodule(module, path=None):
'''Backwards compatible interface.
Call readmodule_ex() and then only keep Class objects from the
resulting dictionary.'''
- dict = _readmodule(module, path)
res = {}
- for key, value in dict.items():
+ for key, value in _readmodule(module, path or []).items():
if isinstance(value, Class):
res[key] = value
return res
-def readmodule_ex(module, path=[]):
+def readmodule_ex(module, path=None):
'''Read a module file and return a dictionary of classes.
Search for MODULE in PATH and sys.path, read and parse the
module and return a dictionary with one entry for each class
found in the module.
+ '''
+ return _readmodule(module, path or [])
+
+def _readmodule(module, path, inpackage=None):
+ '''Do the hard work for readmodule[_ex].
- If INPACKAGE is true, it must be the dotted name of the package in
+ If INPACKAGE is given, it must be the dotted name of the package in
which we are searching for a submodule, and then PATH must be the
package search path; otherwise, we are searching for a top-level
module, and PATH is combined with sys.path.
'''
- return _readmodule(module, path)
-
-def _readmodule(module, path, inpackage=None):
- '''Do the hard work for readmodule[_ex].'''
# Compute the full module name (prepending inpackage if set)
- if inpackage:
+ if inpackage is not None:
fullmodule = "%s.%s" % (inpackage, module)
else:
fullmodule = module
dict = {}
# Check if it is a built-in module; we don't do much for these
- if module in sys.builtin_module_names and not inpackage:
+ if module in sys.builtin_module_names and inpackage is None:
_modules[module] = dict
return dict
package = module[:i]
submodule = module[i+1:]
parent = _readmodule(package, path, inpackage)
- if inpackage:
+ if inpackage is not None:
package = "%s.%s" % (inpackage, package)
return _readmodule(submodule, parent['__path__'], package)
# Search the path for the module
f = None
- if inpackage:
- f, file, (suff, mode, type) = imp.find_module(module, path)
+ if inpackage is not None:
+ f, fname, (_s, _m, ty) = imp.find_module(module, path)
else:
- f, file, (suff, mode, type) = imp.find_module(module, path + sys.path)
- if type == imp.PKG_DIRECTORY:
- dict['__path__'] = [file]
- path = [file] + path
- f, file, (suff, mode, type) = imp.find_module('__init__', [file])
+ f, fname, (_s, _m, ty) = imp.find_module(module, path + sys.path)
+ if ty == imp.PKG_DIRECTORY:
+ dict['__path__'] = [fname]
+ path = [fname] + path
+ f, fname, (_s, _m, ty) = imp.find_module('__init__', [fname])
_modules[fullmodule] = dict
- if type != imp.PY_SOURCE:
+ if ty != imp.PY_SOURCE:
# not Python source, can't do anything with this module
f.close()
return dict
g = tokenize.generate_tokens(f.readline)
try:
- for tokentype, token, start, end, line in g:
+ for tokentype, token, start, _end, _line in g:
if tokentype == DEDENT:
lineno, thisindent = start
# close nested classes and defs
# close previous nested classes and defs
while stack and stack[-1][1] >= thisindent:
del stack[-1]
- tokentype, meth_name, start, end, line = g.next()
+ tokentype, meth_name, start = g.next()[0:3]
if tokentype != NAME:
continue # Syntax error
if stack:
# else it's a nested def
else:
# it's a function
- dict[meth_name] = Function(fullmodule, meth_name, file, lineno)
+ dict[meth_name] = Function(fullmodule, meth_name,
+ fname, lineno)
stack.append((None, thisindent)) # Marker for nested fns
elif token == 'class':
lineno, thisindent = start
# close previous nested classes and defs
while stack and stack[-1][1] >= thisindent:
del stack[-1]
- tokentype, class_name, start, end, line = g.next()
+ tokentype, class_name, start = g.next()[0:3]
if tokentype != NAME:
continue # Syntax error
# parse what follows the class name
- tokentype, token, start, end, line = g.next()
+ tokentype, token, start = g.next()[0:3]
inherit = None
if token == '(':
names = [] # List of superclasses
level = 1
super = [] # Tokens making up current superclass
while True:
- tokentype, token, start, end, line = g.next()
+ tokentype, token, start = g.next()[0:3]
if token in (')', ',') and level == 1:
n = "".join(super)
if n in dict:
super.append(token)
# expressions in the base list are not supported
inherit = names
- cur_class = Class(fullmodule, class_name, inherit, file, lineno)
+ cur_class = Class(fullmodule, class_name, inherit,
+ fname, lineno)
if not stack:
dict[class_name] = cur_class
stack.append((cur_class, thisindent))
elif token == 'import' and start[1] == 0:
modules = _getnamelist(g)
- for mod, mod2 in modules:
+ for mod, _mod2 in modules:
try:
# Recursively read the imported module
- if not inpackage:
+ if inpackage is None:
_readmodule(mod, path)
else:
try:
name2 = None
names.append((name, name2))
while token != "," and "\n" not in token:
- tokentype, token, start, end, line = g.next()
+ token = g.next()[1]
if token != ",":
break
return names
# name is the dotted name, or None if there was no dotted name,
# and token is the next input token.
parts = []
- tokentype, token, start, end, line = g.next()
+ tokentype, token = g.next()[0:2]
if tokentype != NAME and token != '*':
return (None, token)
parts.append(token)
while True:
- tokentype, token, start, end, line = g.next()
+ tokentype, token = g.next()[0:2]
if token != '.':
break
- tokentype, token, start, end, line = g.next()
+ tokentype, token = g.next()[0:2]
if tokentype != NAME:
break
parts.append(token)