Back to index

python3.2  3.2.2
Classes | Functions | Variables
pyclbr Namespace Reference

Classes

class  Class
class  Function

Functions

def readmodule
def readmodule_ex
def _readmodule
def _getnamelist
def _getname
def _main

Variables

list __all__ = ["readmodule", "readmodule_ex", "Class", "Function"]
dictionary _modules = {}

Detailed Description

Parse a Python module and describe its classes and methods.

Parse enough of a Python file to recognize imports and class and
method definitions, and to find out the superclasses of a class.

The interface consists of a single function:
readmodule_ex(module [, path])
where module is the name of a Python module, and path is an optional
list of directories where the module is to be searched.  If present,
path is prepended to the system search path sys.path.  The return
value is a dictionary.  The keys of the dictionary are the names of
the classes defined in the module (including classes that are defined
via the from XXX import YYY construct).  The values are class
instances of the class Class defined here.  One special key/value pair
is present for packages: the key '__path__' has a list as its value
which contains the package search path.

A class is described by the class Class in this module.  Instances
of this class have the following instance variables:
module -- the module name
name -- the name of the class
super -- a list of super classes (Class instances)
methods -- a dictionary of methods
file -- the file in which the class was defined
lineno -- the line in the file on which the class statement occurred
The dictionary of methods uses the method names as keys and the line
numbers on which the method was defined as values.
If the name of a super class is not recognized, the corresponding
entry in the list of super classes is not a class instance but a
string giving the name of the super class.  Since import statements
are recognized and imported modules are scanned as well, this
shouldn't happen often.

A function is described by the class Function in this module.
Instances of this class have the following instance variables:
module -- the module name
name -- the name of the class
file -- the file in which the class was defined
lineno -- the line in the file on which the class statement occurred

Function Documentation

def pyclbr._getname (   g) [private]

Definition at line 297 of file pyclbr.py.

00297 
00298 def _getname(g):
00299     # Helper to get a dotted name, return a pair (name, token) where
00300     # name is the dotted name, or None if there was no dotted name,
00301     # and token is the next input token.
00302     parts = []
00303     tokentype, token = next(g)[0:2]
00304     if tokentype != NAME and token != '*':
00305         return (None, token)
00306     parts.append(token)
00307     while True:
00308         tokentype, token = next(g)[0:2]
00309         if token != '.':
00310             break
00311         tokentype, token = next(g)[0:2]
00312         if tokentype != NAME:
00313             break
00314         parts.append(token)
00315     return (".".join(parts), token)

Here is the caller graph for this function:

def pyclbr._getnamelist (   g) [private]

Definition at line 277 of file pyclbr.py.

00277 
00278 def _getnamelist(g):
00279     # Helper to get a comma-separated list of dotted names plus 'as'
00280     # clauses.  Return a list of pairs (name, name2) where name2 is
00281     # the 'as' name, or None if there is no 'as' clause.
00282     names = []
00283     while True:
00284         name, token = _getname(g)
00285         if not name:
00286             break
00287         if token == 'as':
00288             name2, token = _getname(g)
00289         else:
00290             name2 = None
00291         names.append((name, name2))
00292         while token != "," and "\n" not in token:
00293             token = next(g)[1]
00294         if token != ",":
00295             break
00296     return names

Here is the call graph for this function:

Here is the caller graph for this function:

def pyclbr._main ( ) [private]

Definition at line 316 of file pyclbr.py.

00316 
00317 def _main():
00318     # Main program for testing.
00319     import os
00320     mod = sys.argv[1]
00321     if os.path.exists(mod):
00322         path = [os.path.dirname(mod)]
00323         mod = os.path.basename(mod)
00324         if mod.lower().endswith(".py"):
00325             mod = mod[:-3]
00326     else:
00327         path = []
00328     dict = readmodule_ex(mod, path)
00329     objs = list(dict.values())
00330     objs.sort(key=lambda a: getattr(a, 'lineno', 0))
00331     for obj in objs:
00332         if isinstance(obj, Class):
00333             print("class", obj.name, obj.super, obj.lineno)
00334             methods = sorted(obj.methods.items(), key=itemgetter(1))
00335             for name, lineno in methods:
00336                 if name != "__path__":
00337                     print("  def", name, lineno)
00338         elif isinstance(obj, Function):
00339             print("def", obj.name, obj.lineno)

Here is the call graph for this function:

def pyclbr._readmodule (   module,
  path,
  inpackage = None 
) [private]
Do the hard work for readmodule[_ex].

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.

Definition at line 97 of file pyclbr.py.

00097 
00098 def _readmodule(module, path, inpackage=None):
00099     '''Do the hard work for readmodule[_ex].
00100 
00101     If INPACKAGE is given, it must be the dotted name of the package in
00102     which we are searching for a submodule, and then PATH must be the
00103     package search path; otherwise, we are searching for a top-level
00104     module, and PATH is combined with sys.path.
00105     '''
00106     # Compute the full module name (prepending inpackage if set)
00107     if inpackage is not None:
00108         fullmodule = "%s.%s" % (inpackage, module)
00109     else:
00110         fullmodule = module
00111 
00112     # Check in the cache
00113     if fullmodule in _modules:
00114         return _modules[fullmodule]
00115 
00116     # Initialize the dict for this module's contents
00117     dict = {}
00118 
00119     # Check if it is a built-in module; we don't do much for these
00120     if module in sys.builtin_module_names and inpackage is None:
00121         _modules[module] = dict
00122         return dict
00123 
00124     # Check for a dotted module name
00125     i = module.rfind('.')
00126     if i >= 0:
00127         package = module[:i]
00128         submodule = module[i+1:]
00129         parent = _readmodule(package, path, inpackage)
00130         if inpackage is not None:
00131             package = "%s.%s" % (inpackage, package)
00132         return _readmodule(submodule, parent['__path__'], package)
00133 
00134     # Search the path for the module
00135     f = None
00136     if inpackage is not None:
00137         f, fname, (_s, _m, ty) = imp.find_module(module, path)
00138     else:
00139         f, fname, (_s, _m, ty) = imp.find_module(module, path + sys.path)
00140     if ty == imp.PKG_DIRECTORY:
00141         dict['__path__'] = [fname]
00142         path = [fname] + path
00143         f, fname, (_s, _m, ty) = imp.find_module('__init__', [fname])
00144     _modules[fullmodule] = dict
00145     if ty != imp.PY_SOURCE:
00146         # not Python source, can't do anything with this module
00147         f.close()
00148         return dict
00149 
00150     stack = [] # stack of (class, indent) pairs
00151 
00152     g = tokenize.generate_tokens(f.readline)
00153     try:
00154         for tokentype, token, start, _end, _line in g:
00155             if tokentype == DEDENT:
00156                 lineno, thisindent = start
00157                 # close nested classes and defs
00158                 while stack and stack[-1][1] >= thisindent:
00159                     del stack[-1]
00160             elif token == 'def':
00161                 lineno, thisindent = start
00162                 # close previous nested classes and defs
00163                 while stack and stack[-1][1] >= thisindent:
00164                     del stack[-1]
00165                 tokentype, meth_name, start = next(g)[0:3]
00166                 if tokentype != NAME:
00167                     continue # Syntax error
00168                 if stack:
00169                     cur_class = stack[-1][0]
00170                     if isinstance(cur_class, Class):
00171                         # it's a method
00172                         cur_class._addmethod(meth_name, lineno)
00173                     # else it's a nested def
00174                 else:
00175                     # it's a function
00176                     dict[meth_name] = Function(fullmodule, meth_name,
00177                                                fname, lineno)
00178                 stack.append((None, thisindent)) # Marker for nested fns
00179             elif token == 'class':
00180                 lineno, thisindent = start
00181                 # close previous nested classes and defs
00182                 while stack and stack[-1][1] >= thisindent:
00183                     del stack[-1]
00184                 tokentype, class_name, start = next(g)[0:3]
00185                 if tokentype != NAME:
00186                     continue # Syntax error
00187                 # parse what follows the class name
00188                 tokentype, token, start = next(g)[0:3]
00189                 inherit = None
00190                 if token == '(':
00191                     names = [] # List of superclasses
00192                     # there's a list of superclasses
00193                     level = 1
00194                     super = [] # Tokens making up current superclass
00195                     while True:
00196                         tokentype, token, start = next(g)[0:3]
00197                         if token in (')', ',') and level == 1:
00198                             n = "".join(super)
00199                             if n in dict:
00200                                 # we know this super class
00201                                 n = dict[n]
00202                             else:
00203                                 c = n.split('.')
00204                                 if len(c) > 1:
00205                                     # super class is of the form
00206                                     # module.class: look in module for
00207                                     # class
00208                                     m = c[-2]
00209                                     c = c[-1]
00210                                     if m in _modules:
00211                                         d = _modules[m]
00212                                         if c in d:
00213                                             n = d[c]
00214                             names.append(n)
00215                             super = []
00216                         if token == '(':
00217                             level += 1
00218                         elif token == ')':
00219                             level -= 1
00220                             if level == 0:
00221                                 break
00222                         elif token == ',' and level == 1:
00223                             pass
00224                         # only use NAME and OP (== dot) tokens for type name
00225                         elif tokentype in (NAME, OP) and level == 1:
00226                             super.append(token)
00227                         # expressions in the base list are not supported
00228                     inherit = names
00229                 cur_class = Class(fullmodule, class_name, inherit,
00230                                   fname, lineno)
00231                 if not stack:
00232                     dict[class_name] = cur_class
00233                 stack.append((cur_class, thisindent))
00234             elif token == 'import' and start[1] == 0:
00235                 modules = _getnamelist(g)
00236                 for mod, _mod2 in modules:
00237                     try:
00238                         # Recursively read the imported module
00239                         if inpackage is None:
00240                             _readmodule(mod, path)
00241                         else:
00242                             try:
00243                                 _readmodule(mod, path, inpackage)
00244                             except ImportError:
00245                                 _readmodule(mod, [])
00246                     except:
00247                         # If we can't find or parse the imported module,
00248                         # too bad -- don't die here.
00249                         pass
00250             elif token == 'from' and start[1] == 0:
00251                 mod, token = _getname(g)
00252                 if not mod or token != "import":
00253                     continue
00254                 names = _getnamelist(g)
00255                 try:
00256                     # Recursively read the imported module
00257                     d = _readmodule(mod, path, inpackage)
00258                 except:
00259                     # If we can't find or parse the imported module,
00260                     # too bad -- don't die here.
00261                     continue
00262                 # add any classes that were defined in the imported module
00263                 # to our name space if they were mentioned in the list
00264                 for n, n2 in names:
00265                     if n in d:
00266                         dict[n2 or n] = d[n]
00267                     elif n == '*':
00268                         # don't add names that start with _
00269                         for n in d:
00270                             if n[0] != '_':
00271                                 dict[n] = d[n]
00272     except StopIteration:
00273         pass
00274 
00275     f.close()
00276     return dict

Here is the call graph for this function:

Here is the caller graph for this function:

def pyclbr.readmodule (   module,
  path = None 
)
Backwards compatible interface.

Call readmodule_ex() and then only keep Class objects from the
resulting dictionary.

Definition at line 76 of file pyclbr.py.

00076 
00077 def readmodule(module, path=None):
00078     '''Backwards compatible interface.
00079 
00080     Call readmodule_ex() and then only keep Class objects from the
00081     resulting dictionary.'''
00082 
00083     res = {}
00084     for key, value in _readmodule(module, path or []).items():
00085         if isinstance(value, Class):
00086             res[key] = value
00087     return res

Here is the call graph for this function:

def pyclbr.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.

Definition at line 88 of file pyclbr.py.

00088 
00089 def readmodule_ex(module, path=None):
00090     '''Read a module file and return a dictionary of classes.
00091 
00092     Search for MODULE in PATH and sys.path, read and parse the
00093     module and return a dictionary with one entry for each class
00094     found in the module.
00095     '''
00096     return _readmodule(module, path or [])

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

list pyclbr.__all__ = ["readmodule", "readmodule_ex", "Class", "Function"]

Definition at line 48 of file pyclbr.py.

Definition at line 50 of file pyclbr.py.