~ubuntu-branches/debian/sid/pydoctor/sid

« back to all changes in this revision

Viewing changes to pydoctor/astbuilder.py

  • Committer: Package Import Robot
  • Author(s): Jelmer Vernooij
  • Date: 2013-09-15 13:58:49 UTC
  • mfrom: (1.1.3)
  • Revision ID: package-import@ubuntu.com-20130915135849-g206zbvqwvz0ptdg
Tags: 0.5b1+bzr603-1
* New upstream snapshot.
* Switch from cdbs to dh.
* Bump standards version to 3.9.4 (no changes).
* Update Vcs header.

Show diffs side-by-side

added added

removed removed

Lines of Context:
64
64
    return MyTransformer().parsesuite(buf)
65
65
 
66
66
 
 
67
def node2dottedname(node):
 
68
    parts = []
 
69
    while isinstance(node, ast.Getattr):
 
70
        parts.append(node.attrname)
 
71
        node = node.expr
 
72
    if isinstance(node, ast.Name):
 
73
        parts.append(node.name)
 
74
    else:
 
75
        return None
 
76
    parts.reverse()
 
77
    return parts
 
78
 
 
79
 
67
80
class ModuleVistor(object):
68
81
    def __init__(self, builder, module):
69
82
        self.builder = builder
85
98
        rawbases = []
86
99
        bases = []
87
100
        baseobjects = []
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)
97
 
            if bob:
98
 
                assert (bob.parentMod is self.builder.currentMod or
99
 
                        bob.parentMod.state > 0)
100
 
            bases.append(base)
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):
 
108
                baseobj = None
 
109
            baseobjects.append(baseobj)
102
110
 
103
111
        cls = self.builder.pushClass(node.name, node.doc)
 
112
        cls.decorators = []
 
113
        cls.rawbases = rawbases
 
114
        cls.bases = bases
 
115
        cls.baseobjects = baseobjects
 
116
 
 
117
        def node2data(node):
 
118
            dotted_name = node2dottedname(node)
 
119
            if dotted_name is None:
 
120
                return 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)
 
125
 
 
126
        if node.decorators:
 
127
            for decnode in node.decorators:
 
128
                if isinstance(decnode, ast.CallFunc):
 
129
                    args = []
 
130
                    for arg in decnode.args:
 
131
                        args.append(node2data(arg))
 
132
                    base = node2data(decnode.node)
 
133
                else:
 
134
                    base = node2data(decnode)
 
135
                    args = None
 
136
                cls.decorators.append((base, args))
 
137
 
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
110
 
        cls.bases = bases
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()
117
148
 
118
149
    def visitFrom(self, node):
 
150
        if not isinstance(self.builder.current, model.CanContainImportsDocumentable):
 
151
            self.warning("processing import statement in odd context")
 
152
            return
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
 
158
        else:
 
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 == '*':
126
163
                if mod is None:
130
167
                if mod.all is not None:
131
168
                    names = mod.all
132
169
                else:
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('_')]
135
172
                for n in names:
136
 
                    name2fullname[n] = modname + '.' + n
 
173
                    _localNameToFullName[n] = expandName(n)
137
174
                return
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):
147
185
                    self.system.msg(
148
186
                        "astbuilder",
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
155
 
                    # :/
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() + '.'
161
 
                    ob.name = asname
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)
168
192
                    continue
169
193
            if isinstance(
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)
173
197
 
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.
186
210
        """
187
 
        name2fullname = self.builder.current._name2fullname
 
211
        if not isinstance(self.builder.current, model.CanContainImportsDocumentable):
 
212
            self.warning("processing import statement in odd context")
 
213
            return
 
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)
 
218
            if mod is not None:
 
219
                assert mod.state in [model.PROCESSING, model.PROCESSED]
 
220
                expandName = mod.expandName
 
221
            else:
 
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)
199
231
                        break
200
232
                else:
201
233
                    fullname = '.'.join(parts)
202
 
                    name2fullname[asname] = '.'.join(parts)
 
234
                    _localNameToFullName[asname] = '.'.join(parts)
203
235
            else:
204
 
                name2fullname[asname] = fullname
 
236
                _localNameToFullName[asname] = fullname
205
237
 
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:
209
 
                return
210
 
            if not isinstance(node.nodes[0], ast.AssName):
211
 
                return
212
 
            target = node.nodes[0].name
213
 
            if not isinstance(node.expr, ast.CallFunc):
214
 
                return
215
 
            func = node.expr.node
 
240
            if not isinstance(expr, ast.CallFunc):
 
241
                return
 
242
            func = expr.node
216
243
            if not isinstance(func, ast.Name):
217
244
                return
218
245
            func = func.name
219
 
            args = node.expr.args
 
246
            args = expr.args
220
247
            if len(args) != 1:
221
248
                return
222
249
            arg, = args
231
258
                    else:
232
259
                        target.kind = func.title().replace('m', ' M')
233
260
 
 
261
    def _handleAliasing(self, target, expr):
 
262
        dottedname = node2dottedname(expr)
 
263
        if dottedname is None:
 
264
            return
 
265
        if not isinstance(self.builder.current, model.CanContainImportsDocumentable):
 
266
            return
 
267
        c = self.builder.current
 
268
        base = None
 
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()
 
273
        if base:
 
274
            c._localNameToFullName_map[target] = '.'.join([base] + dottedname[1:])
 
275
 
 
276
    def visitAssign(self, node):
 
277
        if len(node.nodes) != 1:
 
278
            return
 
279
        if not isinstance(node.nodes[0], ast.AssName):
 
280
            return
 
281
        target = node.nodes[0].name
 
282
        self._handleOldSchoolDecoration(target, node.expr)
 
283
        self._handleAliasing(target, node.expr)
 
284
 
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
323
374
        else:
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)
325
380
 
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))
358
413
 
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
363
418
        else:
364
419
            prefix, suffix = modname, ''
365
420
        package = self.current.parentMod.parent
366
 
        if package is None:
367
 
            return modname
368
 
        if prefix in package.contents:
369
 
            if givewarning:
 
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
372
 
        else:
373
 
            return modname
 
424
                return package.contents[prefix].fullName() + suffix
 
425
            package = package.parent
 
426
        return modname
374
427
 
375
428
    def parseFile(self, filePath):
376
429
        if filePath in self.ast_cache: