64
64
return MyTransformer().parsesuite(buf)
67
def node2dottedname(node):
69
while isinstance(node, ast.Getattr):
70
parts.append(node.attrname)
72
if isinstance(node, ast.Name):
73
parts.append(node.name)
67
80
class ModuleVistor(object):
68
81
def __init__(self, builder, module):
69
82
self.builder = builder
88
current = self.builder.current
89
101
for n in node.bases:
90
102
str_base = ast_pp.pp(n)
91
103
rawbases.append(str_base)
92
base = current.dottedNameToFullName(str_base)
93
bob = self.system.objForFullName(base)
94
if not bob and self.system.options.resolvealiases:
95
base = self.system.resolveAlias(base)
96
bob = self.system.objForFullName(base)
98
assert (bob.parentMod is self.builder.currentMod or
99
bob.parentMod.state > 0)
101
baseobjects.append(bob)
104
full_name = self.builder.current.expandName(str_base)
105
bases.append(full_name)
106
baseobj = self.system.objForFullName(full_name)
107
if not isinstance(baseobj, model.Class):
109
baseobjects.append(baseobj)
103
111
cls = self.builder.pushClass(node.name, node.doc)
113
cls.rawbases = rawbases
115
cls.baseobjects = baseobjects
118
dotted_name = node2dottedname(node)
119
if dotted_name is None:
121
dotted_name = '.'.join(dotted_name)
122
full_name = self.builder.current.expandName(dotted_name)
123
obj = self.system.objForFullName(full_name)
124
return (dotted_name, full_name, obj)
127
for decnode in node.decorators:
128
if isinstance(decnode, ast.CallFunc):
130
for arg in decnode.args:
131
args.append(node2data(arg))
132
base = node2data(decnode.node)
134
base = node2data(decnode)
136
cls.decorators.append((base, args))
104
138
if node.lineno is not None:
105
139
cls.linenumber = node.lineno
106
140
if cls.parentMod.sourceHref:
107
141
cls.sourceHref = cls.parentMod.sourceHref + '#L' + \
108
142
str(cls.linenumber)
109
cls.rawbases = rawbases
111
cls.baseobjects = baseobjects
112
143
for b in cls.baseobjects:
113
144
if b is not None:
114
145
b.subclasses.append(cls)
116
147
self.builder.popClass()
118
149
def visitFrom(self, node):
150
if not isinstance(self.builder.current, model.CanContainImportsDocumentable):
151
self.warning("processing import statement in odd context")
119
153
modname = self.builder.expandModname(node.modname)
120
154
mod = self.system.getProcessedModule(modname)
121
155
if mod is not None:
122
156
assert mod.state in [model.PROCESSING, model.PROCESSED]
123
name2fullname = self.builder.current._name2fullname
157
expandName = mod.expandName
159
expandName = lambda name: modname + '.' + name
160
_localNameToFullName = self.builder.current._localNameToFullName_map
124
161
for fromname, asname in node.names:
125
162
if fromname == '*':
130
167
if mod.all is not None:
133
names = [k for k in mod.contents.keys()
134
if not k.startswith('_')]
170
names = mod.contents.keys() + mod._localNameToFullName_map.keys()
171
names = [k for k in names if not k.startswith('_')]
136
name2fullname[n] = modname + '.' + n
173
_localNameToFullName[n] = expandName(n)
138
175
if asname is None:
139
176
asname = fromname
143
180
modname in self.system.allobjects:
144
181
mod = self.system.allobjects[modname]
145
182
if isinstance(mod, model.Module) and \
146
fromname in mod.contents:
183
fromname in mod.contents and \
184
(mod.all is None or fromname not in mod.all):
149
187
"moving %r into %r"
150
188
% (mod.contents[fromname].fullName(),
151
189
self.builder.current.fullName()))
152
# this code attempts to preserve "rather a lot" of
153
# invariants assumed by various bits of pydoctor
154
# and that are of course not written down anywhere
156
190
ob = mod.contents[fromname]
157
targetmod = self.builder.current
158
del self.system.allobjects[ob.fullName()]
159
ob.parent = ob.parentMod = targetmod
160
ob.prefix = targetmod.fullName() + '.'
162
self.system.allobjects[ob.fullName()] = ob
163
del mod.contents[fromname]
164
mod.orderedcontents.remove(ob)
165
mod._name2fullname[fromname] = ob.fullName()
166
targetmod.contents[asname] = ob
167
targetmod.orderedcontents.append(ob)
191
ob.reparent(self.builder.current, asname)
170
194
self.system.objForFullName(modname), model.Package):
171
195
self.system.getProcessedModule(modname + '.' + fromname)
172
name2fullname[asname] = modname + '.' + fromname
196
_localNameToFullName[asname] = expandName(fromname)
174
198
def visitImport(self, node):
175
199
"""Process an import statement.
184
208
(dotted_name, as_name) where as_name is None if there was no 'as foo'
185
209
part of the statement.
187
name2fullname = self.builder.current._name2fullname
211
if not isinstance(self.builder.current, model.CanContainImportsDocumentable):
212
self.warning("processing import statement in odd context")
214
_localNameToFullName = self.builder.current._localNameToFullName_map
188
215
for fromname, asname in node.names:
189
216
fullname = self.builder.expandModname(fromname)
190
self.system.getProcessedModule(fullname)
217
mod = self.system.getProcessedModule(fullname)
219
assert mod.state in [model.PROCESSING, model.PROCESSED]
220
expandName = mod.expandName
222
expandName = lambda name: name
191
223
if asname is None:
192
224
asname = fromname.split('.', 1)[0]
193
225
# aaaaargh! python sucks.
195
227
for i, part in enumerate(fullname.split('.')[::-1]):
196
228
if part == asname:
197
229
fullname = '.'.join(parts[:len(parts)-i])
198
name2fullname[asname] = fullname
230
_localNameToFullName[asname] = expandName(fullname)
201
233
fullname = '.'.join(parts)
202
name2fullname[asname] = '.'.join(parts)
234
_localNameToFullName[asname] = '.'.join(parts)
204
name2fullname[asname] = fullname
236
_localNameToFullName[asname] = fullname
206
def visitAssign(self, node):
238
def _handleOldSchoolDecoration(self, target, expr):
207
239
if isinstance(self.builder.current, model.Class):
208
if len(node.nodes) != 1:
210
if not isinstance(node.nodes[0], ast.AssName):
212
target = node.nodes[0].name
213
if not isinstance(node.expr, ast.CallFunc):
215
func = node.expr.node
240
if not isinstance(expr, ast.CallFunc):
216
243
if not isinstance(func, ast.Name):
219
args = node.expr.args
220
247
if len(args) != 1:
232
259
target.kind = func.title().replace('m', ' M')
261
def _handleAliasing(self, target, expr):
262
dottedname = node2dottedname(expr)
263
if dottedname is None:
265
if not isinstance(self.builder.current, model.CanContainImportsDocumentable):
267
c = self.builder.current
269
if dottedname[0] in c._localNameToFullName_map:
270
base = c._localNameToFullName_map[dottedname[0]]
271
elif dottedname[0] in c.contents:
272
base = c.contents[dottedname[0]].fullName()
274
c._localNameToFullName_map[target] = '.'.join([base] + dottedname[1:])
276
def visitAssign(self, node):
277
if len(node.nodes) != 1:
279
if not isinstance(node.nodes[0], ast.AssName):
281
target = node.nodes[0].name
282
self._handleOldSchoolDecoration(target, node.expr)
283
self._handleAliasing(target, node.expr)
234
285
def visitFunction(self, node):
235
286
func = self.builder.pushFunction(node.name, node.doc)
236
287
func.decorators = node.decorators
322
373
obj.parentMod = self.currentMod
324
375
assert obj.parentMod is None
376
# Method-level import to avoid a circular dependency.
377
from pydoctor import epydoc2stan
378
for attrobj in epydoc2stan.extract_fields(obj):
379
self.system.addObject(attrobj)
326
381
def pop(self, obj):
327
382
assert self.current is obj, "%r is not %r"%(self.current, obj)
356
411
findAll(ast, mod)
357
412
visitor.walk(ast, self.ModuleVistor(self, mod))
359
def expandModname(self, modname, givewarning=True):
414
def expandModname(self, modname):
360
415
if '.' in modname:
361
416
prefix, suffix = modname.split('.', 1)
362
417
suffix = '.' + suffix
364
419
prefix, suffix = modname, ''
365
420
package = self.current.parentMod.parent
368
if prefix in package.contents:
421
while package is not None:
422
if prefix in package.contents:
370
423
self.warning("local import", modname)
371
return package.contents[prefix].fullName() + suffix
424
return package.contents[prefix].fullName() + suffix
425
package = package.parent
375
428
def parseFile(self, filePath):
376
429
if filePath in self.ast_cache: