def visitClass(self, node): rawbases = [] bases = [] baseobjects = [] current = self.builder.current for n in node.bases: str_base = ast_pp.pp(n) rawbases.append(str_base) base = current.dottedNameToFullName(str_base) bob = self.system.objForFullName(base) if not bob and self.system.options.resolvealiases: base = self.system.resolveAlias(base) bob = self.system.objForFullName(base) if bob: assert (bob.parentMod is self.builder.currentMod or bob.parentMod.state > 0) bases.append(base) baseobjects.append(bob) cls = self.builder.pushClass(node.name, node.doc) if node.lineno is not None: cls.linenumber = node.lineno if cls.parentMod.sourceHref: cls.sourceHref = cls.parentMod.sourceHref + '#L' + \ str(cls.linenumber) cls.rawbases = rawbases cls.bases = bases cls.baseobjects = baseobjects for b in cls.baseobjects: if b is not None: b.subclasses.append(cls) self.default(node) self.builder.popClass()
def decorator(self, request, tag): decorators = [] if self.ob.decorators: for dec in self.ob.decorators: if isinstance(dec.asList()[0], ast.Name): fn = self.ob.expandName(dec.asList()[0].name) # We don't want to show the deprecated decorator, it shows up # as an infobox if fn == "twisted.python.deprecate.deprecated": break decorators.append(ast_pp.pp(dec)) if self.ob.kind == "Class Method" and "classmethod" not in decorators: decorators.append("classmethod") elif self.ob.kind == "Static Method" and "staticmethod" not in decorators: decorators.append("staticmethod") if decorators: decorator = [("@" + dec, tags.br()) for dec in decorators] else: decorator = () return decorator
def visitFunction(self, node): func = self.builder.pushFunction(node.name, node.doc) func.decorators = node.decorators if isinstance(func.parent, model.Class) and node.decorators: isclassmethod = False isstaticmethod = False for d in node.decorators.nodes: if isinstance(d, ast.Name): if d.name == 'classmethod': isclassmethod = True elif d.name == 'staticmethod': isstaticmethod = True if isstaticmethod: if isclassmethod: self.system.msg('ast', '%r is both class- and static-method?' % (func.fullName(), ), thresh=-1) else: func.kind = 'Static Method' elif isclassmethod: func.kind = 'Class Method' if node.lineno is not None: func.linenumber = node.lineno if func.parentMod.sourceHref: func.sourceHref = func.parentMod.sourceHref + '#L' + \ str(func.linenumber) # ast.Function has a pretty lame representation of # arguments. Let's convert it to a nice concise format # somewhat like what inspect.getargspec returns argnames = node.argnames[:] kwname = starargname = None if node.kwargs: kwname = argnames.pop(-1) if node.varargs: starargname = argnames.pop(-1) defaults = [] for default in node.defaults: try: defaults.append(ast_pp.pp(default)) except (KeyboardInterrupt, SystemExit): raise except Exception as e: self.builder.warning( "unparseable default", "%s: %s %r" % (e.__class__.__name__, e, default)) defaults.append('???') # argh, convert unpacked-arguments from tuples to lists, # because that's what getargspec uses and the unit test # compares it argnames2 = [] for argname in argnames: if isinstance(argname, tuple): argname = list(argname) argnames2.append(argname) func.argspec = (argnames2, starargname, kwname, tuple(defaults)) #self.postpone(func, node.code) self.builder.popFunction()
def visitCallFunc_zope_interface_classImplements(self, funcName, node): clsname = self.builder.current.expandName(ast_pp.pp(node.args[0])) if clsname not in self.system.allobjects: self.builder.system.msg( "parsing", "classImplements on unknown class %r" % clsname) return cls = self.system.allobjects[clsname] addInterfaceInfoToClass( cls, node.args[1:], funcName == 'zope.interface.classImplementsOnly')
def visitCallFunc_twisted_python_util_moduleMovedForSplit(self, funcName, node): # XXX this is rather fragile... origModuleName, newModuleName, moduleDesc, \ projectName, projectURL, globDict = node.args moduleDesc = ast_pp.pp(moduleDesc)[1:-1] projectName = ast_pp.pp(projectName)[1:-1] projectURL = ast_pp.pp(projectURL)[1:-1] modoc = """ %(moduleDesc)s This module is DEPRECATED. It has been split off into a third party package, Twisted %(projectName)s. Please see %(projectURL)s. This is just a place-holder that imports from the third-party %(projectName)s package for backwards compatibility. To use it, you need to install that package. """ % {'moduleDesc': moduleDesc, 'projectName': projectName, 'projectURL': projectURL} self.builder.current.docstring = modoc
def visitCallFunc_zope_interface_classImplements(self, funcName, node): clsname = self.builder.current.dottedNameToFullName( ast_pp.pp(node.args[0])) if clsname not in self.system.allobjects: self.builder.system.msg( "parsing", "classImplements on unknown class %r"%clsname) return cls = self.system.allobjects[clsname] addInterfaceInfoToClass(cls, node.args[1:], funcName == 'zope.interface.classImplementsOnly')
def visitClass(self, node): rawbases = [] bases = [] baseobjects = [] for n in node.bases: str_base = ast_pp.pp(n) rawbases.append(str_base) full_name = self.builder.current.expandName(str_base) bases.append(full_name) baseobj = self.system.objForFullName(full_name) if not isinstance(baseobj, model.Class): baseobj = None baseobjects.append(baseobj) cls = self.builder.pushClass(node.name, node.doc) cls.decorators = [] cls.rawbases = rawbases cls.bases = bases cls.baseobjects = baseobjects def node2data(node): dotted_name = node2dottedname(node) if dotted_name is None: return None dotted_name = '.'.join(dotted_name) full_name = self.builder.current.expandName(dotted_name) obj = self.system.objForFullName(full_name) return (dotted_name, full_name, obj) if node.decorators: for decnode in node.decorators: if isinstance(decnode, ast.CallFunc): args = [] for arg in decnode.args: args.append(node2data(arg)) base = node2data(decnode.node) else: base = node2data(decnode) args = None cls.decorators.append((base, args)) cls.raw_decorators = node.decorators if node.decorators else [] if node.lineno is not None: cls.linenumber = node.lineno if cls.parentMod.sourceHref: cls.sourceHref = cls.parentMod.sourceHref + '#L' + \ str(cls.linenumber) for b in cls.baseobjects: if b is not None: b.subclasses.append(cls) self.default(node) self.builder.popClass()
def visitClass(self, node): rawbases = [] bases = [] baseobjects = [] for n in node.bases: str_base = ast_pp.pp(n) rawbases.append(str_base) full_name = self.builder.current.expandName(str_base) bases.append(full_name) baseobj = self.system.objForFullName(full_name) if not isinstance(baseobj, model.Class): baseobj = None baseobjects.append(baseobj) cls = self.builder.pushClass(node.name, node.doc) cls.decorators = [] cls.rawbases = rawbases cls.bases = bases cls.baseobjects = baseobjects def node2data(node): dotted_name = node2dottedname(node) if dotted_name is None: return None dotted_name = '.'.join(dotted_name) full_name = self.builder.current.expandName(dotted_name) obj = self.system.objForFullName(full_name) return (dotted_name, full_name, obj) if node.decorators: for decnode in node.decorators: if isinstance(decnode, ast.CallFunc): args = [] for arg in decnode.args: args.append(node2data(arg)) base = node2data(decnode.node) else: base = node2data(decnode) args = None cls.decorators.append((base, args)) if node.lineno is not None: cls.linenumber = node.lineno if cls.parentMod.sourceHref: cls.sourceHref = cls.parentMod.sourceHref + '#L' + \ str(cls.linenumber) for b in cls.baseobjects: if b is not None: b.subclasses.append(cls) self.default(node) self.builder.popClass()
def visitCallFunc_twisted_python_util_moduleMovedForSplit( self, funcName, node): # XXX this is rather fragile... origModuleName, newModuleName, moduleDesc, projectName, projectURL, globDict = ( node.args) moduleDesc = ast_pp.pp(moduleDesc)[1:-1] projectName = ast_pp.pp(projectName)[1:-1] projectURL = ast_pp.pp(projectURL)[1:-1] modoc = """ %(moduleDesc)s This module is DEPRECATED. It has been split off into a third party package, Twisted %(projectName)s. Please see %(projectURL)s. This is just a place-holder that imports from the third-party %(projectName)s package for backwards compatibility. To use it, you need to install that package. """ % { "moduleDesc": moduleDesc, "projectName": projectName, "projectURL": projectURL, } self.builder.current.docstring = modoc
def visitFunction(self, node): func = self.builder.pushFunction(node.name, node.doc) func.decorators = node.decorators if isinstance(func.parent, model.Class) and node.decorators: isclassmethod = False isstaticmethod = False for d in node.decorators.nodes: if isinstance(d, ast.Name): if d.name == 'classmethod': isclassmethod = True elif d.name == 'staticmethod': isstaticmethod = True if isstaticmethod: if isclassmethod: self.system.msg( 'ast', '%r is both class- and static-method?'%( func.fullName(),), thresh=-1) else: func.kind = 'Static Method' elif isclassmethod: func.kind = 'Class Method' if node.lineno is not None: func.linenumber = node.lineno if func.parentMod.sourceHref: func.sourceHref = func.parentMod.sourceHref + '#L' + \ str(func.linenumber) # ast.Function has a pretty lame representation of # arguments. Let's convert it to a nice concise format # somewhat like what inspect.getargspec returns argnames = node.argnames[:] kwname = starargname = None if node.kwargs: kwname = argnames.pop(-1) if node.varargs: starargname = argnames.pop(-1) defaults = [] for default in node.defaults: try: defaults.append(ast_pp.pp(default)) except (KeyboardInterrupt, SystemExit): raise except Exception, e: self.builder.warning("unparseable default", "%s: %s %r"%(e.__class__.__name__, e, default)) defaults.append('???')
def addInterfaceInfoToModule(module, interfaceargs): for arg in interfaceargs: if not isinstance(arg, tuple): fullName = module.expandName(ast_pp.pp(arg)) else: fullName = arg[1] module.implements_directly.append(fullName) obj = module.system.objForFullName(fullName) if obj is not None: if not obj.isinterface: obj.system.msg( 'zopeinterface', 'probable interface %r not marked as such'%obj, thresh=1) obj.isinterface = True obj.kind = "Interface" obj.implementedby_directly = [] obj.implementedby_directly.append(module)
def addInterfaceInfoToModule(module, interfaceargs): for arg in interfaceargs: if not isinstance(arg, tuple): fullName = module.expandName(ast_pp.pp(arg)) else: fullName = arg[1] module.implements_directly.append(fullName) obj = module.system.objForFullName(fullName) if obj is not None: if not obj.isinterface: obj.system.msg('zopeinterface', 'probable interface %r not marked as such' % obj, thresh=1) obj.isinterface = True obj.kind = "Interface" obj.implementedby_directly = [] obj.implementedby_directly.append(module)
def decorator(self, request, tag): if self.ob.decorators: decorators = [ast_pp.pp(dec) for dec in self.ob.decorators] else: decorators = [] if self.ob.kind == "Class Method" \ and 'classmethod' not in decorators: decorators.append('classmethod') elif self.ob.kind == "Static Method" \ and 'staticmethod' not in decorators: decorators.append('staticmethod') if decorators: decorator = [('@' + dec, tags.br()) for dec in decorators] else: decorator = () return decorator
def addInterfaceInfoToClass(cls, interfaceargs, implementsOnly): cls.implementsOnly = implementsOnly if implementsOnly: cls.implements_directly = [] for arg in interfaceargs: fullName = cls.dottedNameToFullName(ast_pp.pp(arg)) if fullName not in cls.system.allobjects: fullName = cls.system.resolveAlias(fullName) cls.implements_directly.append(fullName) obj = cls.system.objForFullName(fullName) if obj is not None: if not obj.isinterface: obj.system.msg('zopeinterface', 'probable interface %r not marked as such' % obj, thresh=1) obj.isinterface = True obj.kind = "Interface" obj.implementedby_directly = [] obj.implementedby_directly.append(cls.fullName())
def addInterfaceInfoToClass(cls, interfaceargs, implementsOnly): cls.implementsOnly = implementsOnly if implementsOnly: cls.implements_directly = [] for arg in interfaceargs: fullName = cls.dottedNameToFullName(ast_pp.pp(arg)) if fullName not in cls.system.allobjects: fullName = cls.system.resolveAlias(fullName) cls.implements_directly.append(fullName) obj = cls.system.objForFullName(fullName) if obj is not None: if not obj.isinterface: obj.system.msg( 'zopeinterface', 'probable interface %r not marked as such'%obj, thresh=1) obj.isinterface = True obj.kind = "Interface" obj.implementedby_directly = [] obj.implementedby_directly.append(cls.fullName())
def addInterfaceInfoToClass(cls, interfaceargs, implementsOnly): cls.implementsOnly = implementsOnly if implementsOnly: cls.implements_directly = [] for arg in interfaceargs: if not isinstance(arg, tuple): fullName = cls.expandName(ast_pp.pp(arg)) else: fullName = arg[1] cls.implements_directly.append(fullName) obj = cls.system.objForFullName(fullName) if obj is not None: if not obj.isinterface: obj.system.msg( 'zopeinterface', 'probable interface %r not marked as such'%obj, thresh=1) obj.isinterface = True obj.kind = "Interface" obj.implementedby_directly = [] obj.implementedby_directly.append(cls)
def addInterfaceInfoToClass(cls, interfaceargs, implementsOnly): cls.implementsOnly = implementsOnly if implementsOnly: cls.implements_directly = [] for arg in interfaceargs: if not isinstance(arg, tuple): fullName = cls.expandName(ast_pp.pp(arg)) else: fullName = arg[1] cls.implements_directly.append(fullName) obj = cls.system.objForFullName(fullName) if obj is not None: if not obj.isinterface: obj.system.msg('zopeinterface', 'probable interface %r not marked as such' % obj, thresh=1) obj.isinterface = True obj.kind = "Interface" obj.implementedby_directly = [] obj.implementedby_directly.append(cls)
def funcNameFromCall(self, node): str_base = ast_pp.pp(node.node) return self.builder.current.dottedNameToFullName(str_base)
def funcNameFromCall(self, node): str_base = ast_pp.pp(node.node) return self.builder.current.expandName(str_base)
def visitAssign(self, node): # i would like pattern matching in python please # if match(Assign([AssName(?name, _)], CallFunc(?funcName, [Const(?docstring)])), node): # ... sup = lambda: super(ZopeInterfaceModuleVisitor, self).visitAssign(node) if isinstance(self.builder.current, model.Module) and \ ast_pp.pp(node) == 'Interface = interface.Interface\n': # warner!!! n2fn = self.builder.current._name2fullname n2fn['Interface'] = 'zope.interface.Interface' return sup() if len(node.nodes) != 1 or \ not isinstance(node.nodes[0], ast.AssName) or \ not isinstance(node.expr, ast.CallFunc): return sup() funcName = self.funcNameFromCall(node.expr) if isinstance(self.builder.current, model.Module): name = node.nodes[0].name args = node.expr.args ob = self.system.objForFullName(funcName) if ob is not None and isinstance( ob, model.Class) and ob.isinterfaceclass: interface = self.builder.pushClass(name, "...") self.builder.system.msg('parsing', 'new interface') interface.isinterface = True interface.implementedby_directly = [] interface.linenumber = node.lineno self.builder.popClass() return sup() elif not isinstance(self.builder.current, model.Class): return sup() def pushAttribute(docstring, kind): attr = self.builder._push(Attribute, node.nodes[0].name, docstring) attr.linenumber = node.lineno attr.kind = kind if attr.parentMod.sourceHref: attr.sourceHref = attr.parentMod.sourceHref + '#L' + \ str(attr.linenumber) self.builder._pop(Attribute) def extractStringLiteral(node): if isinstance(node, ast.Const) and isinstance(node.value, str): return node.value elif isinstance(node, ast.CallFunc) \ and isinstance(node.node, ast.Name) \ and node.node.name == '_' \ and len(node.args) == 1 \ and isinstance(node.args[0], ast.Const) \ and isinstance(node.args[0].value, str): return node.args[0].value def handleSchemaField(kind): #print node.expr descriptions = [ arg for arg in node.expr.args if isinstance(arg, ast.Keyword) and arg.name == 'description' ] docstring = None if len(descriptions) > 1: self.builder.system.msg('parsing', 'xxx') elif len(descriptions) == 1: docstring = extractStringLiteral(descriptions[0].expr) pushAttribute(docstring, kind) if funcName == 'zope.interface.Attribute': args = node.expr.args if len(args) != 1: return sup() pushAttribute(extractStringLiteral(args[0]), "Attribute") return sup() if schema_prog.match(funcName): kind = schema_prog.match(funcName).group(1) handleSchemaField(kind) return sup() cls = self.builder.system.objForFullName(funcName) if cls and isinstance(cls, ZopeInterfaceClass) and cls.isschemafield: handleSchemaField(cls.name) return sup()
def pp_test(source): assert ast_pp.pp(parse(source)) == source
def visitAssign(self, node): # i would like pattern matching in python please # if match(Assign([AssName(?name, _)], CallFunc(?funcName, [Const(?docstring)])), node): # ... sup = lambda : super(ZopeInterfaceModuleVisitor, self).visitAssign(node) if isinstance(self.builder.current, model.Module) and \ ast_pp.pp(node) == 'Interface = interface.Interface\n': # warner!!! n2fn = self.builder.current._name2fullname n2fn['Interface'] = 'zope.interface.Interface' return sup() if len(node.nodes) != 1 or \ not isinstance(node.nodes[0], ast.AssName) or \ not isinstance(node.expr, ast.CallFunc): return sup() funcName = self.funcNameFromCall(node.expr) if isinstance(self.builder.current, model.Module): name = node.nodes[0].name args = node.expr.args ob = self.system.objForFullName(funcName) if ob is not None and isinstance(ob, model.Class) and ob.isinterfaceclass: interface = self.builder.pushClass(name, "...") self.builder.system.msg('parsing', 'new interface') interface.isinterface = True interface.implementedby_directly = [] interface.linenumber = node.lineno self.builder.popClass() return sup() elif not isinstance(self.builder.current, model.Class): return sup() def pushAttribute(docstring, kind): attr = self.builder._push(Attribute, node.nodes[0].name, docstring) attr.linenumber = node.lineno attr.kind = kind if attr.parentMod.sourceHref: attr.sourceHref = attr.parentMod.sourceHref + '#L' + \ str(attr.linenumber) self.builder._pop(Attribute) def extractStringLiteral(node): if isinstance(node, ast.Const) and isinstance(node.value, str): return node.value elif isinstance(node, ast.CallFunc) \ and isinstance(node.node, ast.Name) \ and node.node.name == '_' \ and len(node.args) == 1 \ and isinstance(node.args[0], ast.Const) \ and isinstance(node.args[0].value, str): return node.args[0].value def handleSchemaField(kind): #print node.expr descriptions = [arg for arg in node.expr.args if isinstance(arg, ast.Keyword) and arg.name == 'description'] docstring = None if len(descriptions) > 1: self.builder.system.msg('parsing', 'xxx') elif len(descriptions) == 1: docstring = extractStringLiteral(descriptions[0].expr) pushAttribute(docstring, kind) if funcName == 'zope.interface.Attribute': args = node.expr.args if len(args) != 1: return sup() pushAttribute(extractStringLiteral(args[0]), "Attribute") return sup() if schema_prog.match(funcName): kind = schema_prog.match(funcName).group(1) handleSchemaField(kind) return sup() cls = self.builder.system.objForFullName(funcName) if cls and isinstance(cls, ZopeInterfaceClass) and cls.isschemafield: handleSchemaField(cls.name) return sup()