blob: 2c798df233b8ebd849cbf818f5aebc5d0561363f [file] [log] [blame]
csabella246ff3b2017-07-03 21:31:25 -04001"""Parse a Python module and describe its classes and functions.
Sjoerd Mullender8cb4b1f1995-07-28 09:30:01 +00002
Guido van Rossum0a6f9542002-12-03 08:14:35 +00003Parse enough of a Python file to recognize imports and class and
csabella246ff3b2017-07-03 21:31:25 -04004function definitions, and to find out the superclasses of a class.
Sjoerd Mullender8cb4b1f1995-07-28 09:30:01 +00005
6The interface consists of a single function:
csabella246ff3b2017-07-03 21:31:25 -04007 readmodule_ex(module, path=None)
Guido van Rossum0a6f9542002-12-03 08:14:35 +00008where module is the name of a Python module, and path is an optional
9list of directories where the module is to be searched. If present,
csabella246ff3b2017-07-03 21:31:25 -040010path is prepended to the system search path sys.path. The return value
11is a dictionary. The keys of the dictionary are the names of the
12classes and functions defined in the module (including classes that are
13defined via the from XXX import YYY construct). The values are
14instances of classes Class and Function. One special key/value pair is
15present for packages: the key '__path__' has a list as its value which
16contains the package search path.
Sjoerd Mullender8cb4b1f1995-07-28 09:30:01 +000017
csabella246ff3b2017-07-03 21:31:25 -040018Classes and Functions have a common superclass: _Object. Every instance
19has the following attributes:
20 module -- name of the module;
21 name -- name of the object;
22 file -- file in which the object is defined;
23 lineno -- line in the file where the object's definition starts;
24 parent -- parent of this object, if any;
25 children -- nested objects contained in this object.
26The 'children' attribute is a dictionary mapping names to objects.
27
28Instances of Function describe functions with the attributes from _Object.
29
30Instances of Class describe classes with the attributes from _Object,
31plus the following:
32 super -- list of super classes (Class instances if possible);
33 methods -- mapping of method names to beginning line numbers.
Sjoerd Mullender8cb4b1f1995-07-28 09:30:01 +000034If the name of a super class is not recognized, the corresponding
35entry in the list of super classes is not a class instance but a
36string giving the name of the super class. Since import statements
37are recognized and imported modules are scanned as well, this
38shouldn't happen often.
Guido van Rossum4b8c6ea2000-02-04 15:39:30 +000039"""
Sjoerd Mullender8cb4b1f1995-07-28 09:30:01 +000040
Brett Cannonee78a2b2012-05-12 17:43:17 -040041import io
Sjoerd Mullender8cb4b1f1995-07-28 09:30:01 +000042import sys
Eric Snow6029e082014-01-25 15:32:46 -070043import importlib.util
Christian Heimes81ee3ef2008-05-04 22:42:01 +000044import tokenize
45from token import NAME, DEDENT, OP
Sjoerd Mullender8cb4b1f1995-07-28 09:30:01 +000046
Guido van Rossum0ed7aa12002-12-02 14:54:20 +000047__all__ = ["readmodule", "readmodule_ex", "Class", "Function"]
Skip Montanaroc62c81e2001-02-12 02:00:42 +000048
csabella246ff3b2017-07-03 21:31:25 -040049_modules = {} # Initialize cache of modules we've seen.
Sjoerd Mullender8cb4b1f1995-07-28 09:30:01 +000050
csabella246ff3b2017-07-03 21:31:25 -040051
52class _Object:
53 "Informaton about Python class or function."
54 def __init__(self, module, name, file, lineno, parent):
Tim Peters2344fae2001-01-15 00:50:52 +000055 self.module = module
56 self.name = name
Tim Peters2344fae2001-01-15 00:50:52 +000057 self.file = file
58 self.lineno = lineno
csabella246ff3b2017-07-03 21:31:25 -040059 self.parent = parent
60 self.children = {}
61
62 def _addchild(self, name, obj):
63 self.children[name] = obj
64
65
66class Function(_Object):
67 "Information about a Python function, including methods."
68 def __init__(self, module, name, file, lineno, parent=None):
69 _Object.__init__(self, module, name, file, lineno, parent)
70
71
72class Class(_Object):
73 "Information about a Python class."
74 def __init__(self, module, name, super, file, lineno, parent=None):
75 _Object.__init__(self, module, name, file, lineno, parent)
76 self.super = [] if super is None else super
77 self.methods = {}
Sjoerd Mullender8cb4b1f1995-07-28 09:30:01 +000078
Tim Peters2344fae2001-01-15 00:50:52 +000079 def _addmethod(self, name, lineno):
80 self.methods[name] = lineno
Sjoerd Mullender8cb4b1f1995-07-28 09:30:01 +000081
csabella246ff3b2017-07-03 21:31:25 -040082
83def _nest_function(ob, func_name, lineno):
84 "Return a Function after nesting within ob."
85 newfunc = Function(ob.module, func_name, ob.file, lineno, ob)
86 ob._addchild(func_name, newfunc)
87 if isinstance(ob, Class):
88 ob._addmethod(func_name, lineno)
89 return newfunc
90
91def _nest_class(ob, class_name, lineno, super=None):
92 "Return a Class after nesting within ob."
93 newclass = Class(ob.module, class_name, super, ob.file, lineno, ob)
94 ob._addchild(class_name, newclass)
95 return newclass
Guido van Rossuma3b4a331999-06-10 14:39:39 +000096
Christian Heimes81ee3ef2008-05-04 22:42:01 +000097def readmodule(module, path=None):
csabella246ff3b2017-07-03 21:31:25 -040098 """Return Class objects for the top-level classes in module.
Guido van Rossuma3b4a331999-06-10 14:39:39 +000099
csabella246ff3b2017-07-03 21:31:25 -0400100 This is the original interface, before Functions were added.
101 """
Guido van Rossuma3b4a331999-06-10 14:39:39 +0000102
Tim Peters2344fae2001-01-15 00:50:52 +0000103 res = {}
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000104 for key, value in _readmodule(module, path or []).items():
Guido van Rossum0ed7aa12002-12-02 14:54:20 +0000105 if isinstance(value, Class):
Tim Peters2344fae2001-01-15 00:50:52 +0000106 res[key] = value
107 return res
Guido van Rossuma3b4a331999-06-10 14:39:39 +0000108
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000109def readmodule_ex(module, path=None):
csabella246ff3b2017-07-03 21:31:25 -0400110 """Return a dictionary with all functions and classes in module.
Sjoerd Mullender8cb4b1f1995-07-28 09:30:01 +0000111
csabella246ff3b2017-07-03 21:31:25 -0400112 Search for module in PATH + sys.path.
113 If possible, include imported superclasses.
114 Do this by reading source, without importing (and executing) it.
115 """
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000116 return _readmodule(module, path or [])
Sjoerd Mullender8cb4b1f1995-07-28 09:30:01 +0000117
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000118def _readmodule(module, path, inpackage=None):
csabella246ff3b2017-07-03 21:31:25 -0400119 """Do the hard work for readmodule[_ex].
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000120
csabella246ff3b2017-07-03 21:31:25 -0400121 If inpackage is given, it must be the dotted name of the package in
Guido van Rossum0ed7aa12002-12-02 14:54:20 +0000122 which we are searching for a submodule, and then PATH must be the
123 package search path; otherwise, we are searching for a top-level
csabella246ff3b2017-07-03 21:31:25 -0400124 module, and path is combined with sys.path.
125 """
126 # Compute the full module name (prepending inpackage if set).
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000127 if inpackage is not None:
Guido van Rossum0ed7aa12002-12-02 14:54:20 +0000128 fullmodule = "%s.%s" % (inpackage, module)
129 else:
130 fullmodule = module
131
csabella246ff3b2017-07-03 21:31:25 -0400132 # Check in the cache.
Guido van Rossum0ed7aa12002-12-02 14:54:20 +0000133 if fullmodule in _modules:
134 return _modules[fullmodule]
135
csabella246ff3b2017-07-03 21:31:25 -0400136 # Initialize the dict for this module's contents.
137 tree = {}
Guido van Rossum3d548711999-06-09 15:49:09 +0000138
csabella246ff3b2017-07-03 21:31:25 -0400139 # Check if it is a built-in module; we don't do much for these.
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000140 if module in sys.builtin_module_names and inpackage is None:
csabella246ff3b2017-07-03 21:31:25 -0400141 _modules[module] = tree
142 return tree
Sjoerd Mullender8cb4b1f1995-07-28 09:30:01 +0000143
csabella246ff3b2017-07-03 21:31:25 -0400144 # Check for a dotted module name.
Guido van Rossum0ed7aa12002-12-02 14:54:20 +0000145 i = module.rfind('.')
146 if i >= 0:
147 package = module[:i]
148 submodule = module[i+1:]
Guido van Rossum0a6f9542002-12-03 08:14:35 +0000149 parent = _readmodule(package, path, inpackage)
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000150 if inpackage is not None:
Guido van Rossum0ed7aa12002-12-02 14:54:20 +0000151 package = "%s.%s" % (inpackage, package)
Petri Lehtinen8d886042012-05-18 21:51:11 +0300152 if not '__path__' in parent:
153 raise ImportError('No package named {}'.format(package))
Guido van Rossum0a6f9542002-12-03 08:14:35 +0000154 return _readmodule(submodule, parent['__path__'], package)
Guido van Rossum0ed7aa12002-12-02 14:54:20 +0000155
csabella246ff3b2017-07-03 21:31:25 -0400156 # Search the path for the module.
Tim Peters2344fae2001-01-15 00:50:52 +0000157 f = None
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000158 if inpackage is not None:
Brett Cannonee78a2b2012-05-12 17:43:17 -0400159 search_path = path
Guido van Rossum0ed7aa12002-12-02 14:54:20 +0000160 else:
Brett Cannonee78a2b2012-05-12 17:43:17 -0400161 search_path = path + sys.path
Eric Snow6029e082014-01-25 15:32:46 -0700162 spec = importlib.util._find_spec_from_path(fullmodule, search_path)
csabella246ff3b2017-07-03 21:31:25 -0400163 _modules[fullmodule] = tree
164 # Is module a package?
Victor Stinner5c13aa12016-03-17 09:06:41 +0100165 if spec.submodule_search_locations is not None:
csabella246ff3b2017-07-03 21:31:25 -0400166 tree['__path__'] = spec.submodule_search_locations
Brett Cannonee78a2b2012-05-12 17:43:17 -0400167 try:
Eric Snow02b9f9d2014-01-06 20:42:59 -0700168 source = spec.loader.get_source(fullmodule)
Brett Cannonee78a2b2012-05-12 17:43:17 -0400169 if source is None:
csabella246ff3b2017-07-03 21:31:25 -0400170 return tree
Brett Cannonee78a2b2012-05-12 17:43:17 -0400171 except (AttributeError, ImportError):
csabella246ff3b2017-07-03 21:31:25 -0400172 # If module is not Python source, we cannot do anything.
173 return tree
Sjoerd Mullender8cb4b1f1995-07-28 09:30:01 +0000174
Victor Stinner5c13aa12016-03-17 09:06:41 +0100175 fname = spec.loader.get_filename(fullmodule)
csabella246ff3b2017-07-03 21:31:25 -0400176 return _create_tree(fullmodule, path, fname, source, tree, inpackage)
Victor Stinner5c13aa12016-03-17 09:06:41 +0100177
csabella246ff3b2017-07-03 21:31:25 -0400178
179def _create_tree(fullmodule, path, fname, source, tree, inpackage):
180 """Return the tree for a particular module.
181
182 fullmodule (full module name), inpackage+module, becomes o.module.
183 path is passed to recursive calls of _readmodule.
184 fname becomes o.file.
185 source is tokenized. Imports cause recursive calls to _readmodule.
186 tree is {} or {'__path__': <submodule search locations>}.
187 inpackage, None or string, is passed to recursive calls of _readmodule.
188
189 The effect of recursive calls is mutation of global _modules.
190 """
Brett Cannonee78a2b2012-05-12 17:43:17 -0400191 f = io.StringIO(source)
192
csabella246ff3b2017-07-03 21:31:25 -0400193 stack = [] # Initialize stack of (class, indent) pairs.
Guido van Rossumad380551999-06-07 15:25:18 +0000194
Guido van Rossum040d7ca2002-08-23 01:36:01 +0000195 g = tokenize.generate_tokens(f.readline)
196 try:
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000197 for tokentype, token, start, _end, _line in g:
Guido van Rossum0a6f9542002-12-03 08:14:35 +0000198 if tokentype == DEDENT:
Guido van Rossum040d7ca2002-08-23 01:36:01 +0000199 lineno, thisindent = start
csabella246ff3b2017-07-03 21:31:25 -0400200 # Close previous nested classes and defs.
Guido van Rossum0a6f9542002-12-03 08:14:35 +0000201 while stack and stack[-1][1] >= thisindent:
202 del stack[-1]
203 elif token == 'def':
204 lineno, thisindent = start
csabella246ff3b2017-07-03 21:31:25 -0400205 # Close previous nested classes and defs.
Guido van Rossum0a6f9542002-12-03 08:14:35 +0000206 while stack and stack[-1][1] >= thisindent:
207 del stack[-1]
csabella246ff3b2017-07-03 21:31:25 -0400208 tokentype, func_name, start = next(g)[0:3]
Guido van Rossum040d7ca2002-08-23 01:36:01 +0000209 if tokentype != NAME:
csabella246ff3b2017-07-03 21:31:25 -0400210 continue # Skip def with syntax error.
211 cur_func = None
Guido van Rossum0a6f9542002-12-03 08:14:35 +0000212 if stack:
csabella246ff3b2017-07-03 21:31:25 -0400213 cur_obj = stack[-1][0]
214 cur_func = _nest_function(cur_obj, func_name, lineno)
Guido van Rossum040d7ca2002-08-23 01:36:01 +0000215 else:
csabella246ff3b2017-07-03 21:31:25 -0400216 # It is just a function.
217 cur_func = Function(fullmodule, func_name, fname, lineno)
218 tree[func_name] = cur_func
219 stack.append((cur_func, thisindent))
Guido van Rossum040d7ca2002-08-23 01:36:01 +0000220 elif token == 'class':
221 lineno, thisindent = start
csabella246ff3b2017-07-03 21:31:25 -0400222 # Close previous nested classes and defs.
Guido van Rossum0a6f9542002-12-03 08:14:35 +0000223 while stack and stack[-1][1] >= thisindent:
224 del stack[-1]
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000225 tokentype, class_name, start = next(g)[0:3]
Guido van Rossum040d7ca2002-08-23 01:36:01 +0000226 if tokentype != NAME:
csabella246ff3b2017-07-03 21:31:25 -0400227 continue # Skip class with syntax error.
228 # Parse what follows the class name.
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000229 tokentype, token, start = next(g)[0:3]
Guido van Rossum040d7ca2002-08-23 01:36:01 +0000230 inherit = None
231 if token == '(':
csabella246ff3b2017-07-03 21:31:25 -0400232 names = [] # Initialize list of superclasses.
Guido van Rossum040d7ca2002-08-23 01:36:01 +0000233 level = 1
csabella246ff3b2017-07-03 21:31:25 -0400234 super = [] # Tokens making up current superclass.
Guido van Rossum040d7ca2002-08-23 01:36:01 +0000235 while True:
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000236 tokentype, token, start = next(g)[0:3]
Guido van Rossum040d7ca2002-08-23 01:36:01 +0000237 if token in (')', ',') and level == 1:
238 n = "".join(super)
csabella246ff3b2017-07-03 21:31:25 -0400239 if n in tree:
240 # We know this super class.
241 n = tree[n]
Guido van Rossum040d7ca2002-08-23 01:36:01 +0000242 else:
243 c = n.split('.')
244 if len(c) > 1:
csabella246ff3b2017-07-03 21:31:25 -0400245 # Super class form is module.class:
246 # look in module for class.
Guido van Rossum040d7ca2002-08-23 01:36:01 +0000247 m = c[-2]
248 c = c[-1]
249 if m in _modules:
250 d = _modules[m]
251 if c in d:
252 n = d[c]
253 names.append(n)
Guido van Rossum0a6f9542002-12-03 08:14:35 +0000254 super = []
Guido van Rossum040d7ca2002-08-23 01:36:01 +0000255 if token == '(':
256 level += 1
257 elif token == ')':
258 level -= 1
259 if level == 0:
260 break
261 elif token == ',' and level == 1:
262 pass
csabella246ff3b2017-07-03 21:31:25 -0400263 # Only use NAME and OP (== dot) tokens for type name.
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000264 elif tokentype in (NAME, OP) and level == 1:
Guido van Rossum040d7ca2002-08-23 01:36:01 +0000265 super.append(token)
csabella246ff3b2017-07-03 21:31:25 -0400266 # Expressions in the base list are not supported.
Guido van Rossum040d7ca2002-08-23 01:36:01 +0000267 inherit = names
csabella246ff3b2017-07-03 21:31:25 -0400268 if stack:
269 cur_obj = stack[-1][0]
270 cur_class = _nest_class(
271 cur_obj, class_name, lineno, inherit)
272 else:
273 cur_class = Class(fullmodule, class_name, inherit,
274 fname, lineno)
275 tree[class_name] = cur_class
Guido van Rossum0a6f9542002-12-03 08:14:35 +0000276 stack.append((cur_class, thisindent))
Guido van Rossum040d7ca2002-08-23 01:36:01 +0000277 elif token == 'import' and start[1] == 0:
278 modules = _getnamelist(g)
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000279 for mod, _mod2 in modules:
Guido van Rossum258cba82002-09-16 16:36:02 +0000280 try:
csabella246ff3b2017-07-03 21:31:25 -0400281 # Recursively read the imported module.
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000282 if inpackage is None:
Guido van Rossum0a6f9542002-12-03 08:14:35 +0000283 _readmodule(mod, path)
Guido van Rossum0ed7aa12002-12-02 14:54:20 +0000284 else:
285 try:
Guido van Rossum0a6f9542002-12-03 08:14:35 +0000286 _readmodule(mod, path, inpackage)
Guido van Rossum0ed7aa12002-12-02 14:54:20 +0000287 except ImportError:
Guido van Rossum0a6f9542002-12-03 08:14:35 +0000288 _readmodule(mod, [])
Guido van Rossum258cba82002-09-16 16:36:02 +0000289 except:
290 # If we can't find or parse the imported module,
291 # too bad -- don't die here.
292 pass
Guido van Rossum040d7ca2002-08-23 01:36:01 +0000293 elif token == 'from' and start[1] == 0:
294 mod, token = _getname(g)
295 if not mod or token != "import":
296 continue
297 names = _getnamelist(g)
Tim Peters2344fae2001-01-15 00:50:52 +0000298 try:
csabella246ff3b2017-07-03 21:31:25 -0400299 # Recursively read the imported module.
Guido van Rossum0a6f9542002-12-03 08:14:35 +0000300 d = _readmodule(mod, path, inpackage)
Tim Peters2344fae2001-01-15 00:50:52 +0000301 except:
Guido van Rossum258cba82002-09-16 16:36:02 +0000302 # If we can't find or parse the imported module,
303 # too bad -- don't die here.
Guido van Rossum040d7ca2002-08-23 01:36:01 +0000304 continue
csabella246ff3b2017-07-03 21:31:25 -0400305 # Add any classes that were defined in the imported module
306 # to our name space if they were mentioned in the list.
Guido van Rossum040d7ca2002-08-23 01:36:01 +0000307 for n, n2 in names:
308 if n in d:
csabella246ff3b2017-07-03 21:31:25 -0400309 tree[n2 or n] = d[n]
Guido van Rossum040d7ca2002-08-23 01:36:01 +0000310 elif n == '*':
csabella246ff3b2017-07-03 21:31:25 -0400311 # Don't add names that start with _.
Guido van Rossum040d7ca2002-08-23 01:36:01 +0000312 for n in d:
Guido van Rossum0a6f9542002-12-03 08:14:35 +0000313 if n[0] != '_':
csabella246ff3b2017-07-03 21:31:25 -0400314 tree[n] = d[n]
Guido van Rossum040d7ca2002-08-23 01:36:01 +0000315 except StopIteration:
316 pass
Guido van Rossumad380551999-06-07 15:25:18 +0000317
Guido van Rossum040d7ca2002-08-23 01:36:01 +0000318 f.close()
csabella246ff3b2017-07-03 21:31:25 -0400319 return tree
320
Guido van Rossumdf9f7a31999-06-08 12:53:21 +0000321
Guido van Rossum040d7ca2002-08-23 01:36:01 +0000322def _getnamelist(g):
csabella246ff3b2017-07-03 21:31:25 -0400323 """Return list of (dotted-name, as-name or None) tuples for token source g.
324
325 An as-name is the name that follows 'as' in an as clause.
326 """
Guido van Rossum040d7ca2002-08-23 01:36:01 +0000327 names = []
328 while True:
329 name, token = _getname(g)
330 if not name:
331 break
332 if token == 'as':
333 name2, token = _getname(g)
334 else:
335 name2 = None
336 names.append((name, name2))
337 while token != "," and "\n" not in token:
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000338 token = next(g)[1]
Guido van Rossum040d7ca2002-08-23 01:36:01 +0000339 if token != ",":
340 break
341 return names
342
csabella246ff3b2017-07-03 21:31:25 -0400343
Guido van Rossum040d7ca2002-08-23 01:36:01 +0000344def _getname(g):
csabella246ff3b2017-07-03 21:31:25 -0400345 "Return (dotted-name or None, next-token) tuple for token source g."
Guido van Rossum040d7ca2002-08-23 01:36:01 +0000346 parts = []
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000347 tokentype, token = next(g)[0:2]
Guido van Rossum040d7ca2002-08-23 01:36:01 +0000348 if tokentype != NAME and token != '*':
349 return (None, token)
350 parts.append(token)
351 while True:
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000352 tokentype, token = next(g)[0:2]
Guido van Rossum040d7ca2002-08-23 01:36:01 +0000353 if token != '.':
354 break
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000355 tokentype, token = next(g)[0:2]
Guido van Rossum040d7ca2002-08-23 01:36:01 +0000356 if tokentype != NAME:
357 break
358 parts.append(token)
359 return (".".join(parts), token)
Guido van Rossum0a6f9542002-12-03 08:14:35 +0000360
csabella246ff3b2017-07-03 21:31:25 -0400361
Guido van Rossum0a6f9542002-12-03 08:14:35 +0000362def _main():
csabella246ff3b2017-07-03 21:31:25 -0400363 "Print module output (default this file) for quick visual check."
Guido van Rossum0a6f9542002-12-03 08:14:35 +0000364 import os
csabella246ff3b2017-07-03 21:31:25 -0400365 try:
366 mod = sys.argv[1]
367 except:
368 mod = __file__
Guido van Rossum0a6f9542002-12-03 08:14:35 +0000369 if os.path.exists(mod):
370 path = [os.path.dirname(mod)]
371 mod = os.path.basename(mod)
372 if mod.lower().endswith(".py"):
373 mod = mod[:-3]
374 else:
375 path = []
csabella246ff3b2017-07-03 21:31:25 -0400376 tree = readmodule_ex(mod, path)
377 lineno_key = lambda a: getattr(a, 'lineno', 0)
378 objs = sorted(tree.values(), key=lineno_key, reverse=True)
379 indent_level = 2
380 while objs:
381 obj = objs.pop()
382 if isinstance(obj, list):
383 # Value is a __path__ key.
384 continue
385 if not hasattr(obj, 'indent'):
386 obj.indent = 0
387
388 if isinstance(obj, _Object):
389 new_objs = sorted(obj.children.values(),
390 key=lineno_key, reverse=True)
391 for ob in new_objs:
392 ob.indent = obj.indent + indent_level
393 objs.extend(new_objs)
Guido van Rossum0a6f9542002-12-03 08:14:35 +0000394 if isinstance(obj, Class):
csabella246ff3b2017-07-03 21:31:25 -0400395 print("{}class {} {} {}"
396 .format(' ' * obj.indent, obj.name, obj.super, obj.lineno))
Guido van Rossum0a6f9542002-12-03 08:14:35 +0000397 elif isinstance(obj, Function):
csabella246ff3b2017-07-03 21:31:25 -0400398 print("{}def {} {}".format(' ' * obj.indent, obj.name, obj.lineno))
Guido van Rossum0a6f9542002-12-03 08:14:35 +0000399
400if __name__ == "__main__":
401 _main()