#!/usr/bin/env python # -*- coding: utf-8 -*- # java2python.mod.basic -> functions to revise generated source strings. from itertools import count from logging import info, warn from os import path from re import sub as rxsub def shebangLine(module): """ yields the canonical python shebang line. """ yield '#!/usr/bin/env python' def encodingLine(encoding='utf-8'): """ returns a function to yield the specified encoding line. Note that this function isn't wired up because the encoding is specified for the source directly, and adding this line produces a syntax error when the compile function is used. """ def line(module): yield '# -*- coding: {0} -*-'.format(encoding) return line def simpleDocString(obj): """ yields multiple lines for a default docstring. This generator works for modules, classes, and functions. """ yield '""" generated source for {0} {1} """'.format(obj.typeName, obj.name) def commentedImports(module, expr): module.factory.comment(parent=module, left=expr, fs='import: {left}') def simpleImports(module, expr): module.factory.expr(parent=module, left=expr, fs='import {left}') def commentedPackages(module, expr): module.factory.comment(parent=module, left=expr, fs='# package: {left}') def namespacePackages(module, expr): source = module.sourceFilename if not source: warn('namespace package not created; source input not named.') return initname = path.join(path.dirname(source), '__init__.py') if path.exists(initname): warn('namespace package not created; __init__.py exists.') return with open(initname, 'w') as initfile: initfile.write('from pkgutil import extend_path\n') initfile.write('__path__ = extend_path(__path__, __name__)\n') # wrong initfile.write('\nfrom {0} import {0}\n'.format(module.name)) info('created __init__.py file for package %s.', expr) def enumConstInts(enum, index, name): return str(index) def enumConstStrings(enum, index, name): return repr(name) scriptTemplate = """\n if __name__ == '__main__': {indent}import sys {indent}{name}.main(sys.argv)""" def scriptMainStanza(module): def filterClass(x): return x.isClass and x.name==module.name def filterMethod(x): return x.isMethod and x.isPublic and x.isStatic and \ x.isVoid and x.name=='main' for cls in [c for c in module.children if filterClass(c)]: if [m for m in cls.children if filterMethod(m)]: yield scriptTemplate.format(indent=module.indent, name=module.name) break def outputSubs(obj, text): subsname = '{0}OutputSubs'.format(obj.typeName) subs = obj.config.every(subsname, []) for sub in subs: for pattern, repl in sub: text = rxsub(pattern, repl, text) return text def overloadedClassMethods(method): """ NB: this implementation does not handle overloaded static (or class) methods, only instance methods. """ cls = method.parent methods = [o for o in cls.children if o.isMethod and o.name==method.name] if len(methods) == 1: return for i, m in enumerate(methods[1:]): args = [p['type'] for p in m.parameters] args = ', '.join(args) m.decorators.append('@{0}.register({1})'.format(method.name, args)) m.name = '{0}_{1}'.format(method.name, i) # for this one only: yield '@overloaded' def maybeClassMethod(method): if method.isStatic and 'classmethod' not in method.decorators: yield '@classmethod' def maybeAbstractMethod(method): if method.parent and method.parent.isInterface: yield '@abstractmethod' def maybeSynchronizedMethod(method): if 'synchronized' in method.modifiers: module = method.parents(lambda x:x.isModule).next() module.needsSyncHelpers = True yield '@synchronized' def globalNameCounter(original, counter=count()): return '__{0}_{1}'.format(original, counter.next()) def getBsrSrc(): from inspect import getsource from java2python.mod.include.bsr import bsr return getsource(bsr) def getSyncHelpersSrc(): from inspect import getsource from java2python.mod.include import sync return getsource(sync) def maybeBsr(module): if getattr(module, 'needsBsrFunc', False): for line in getBsrSrc().split('\n'): yield line def maybeSyncHelpers(module): if getattr(module, 'needsSyncHelpers', False): for line in getSyncHelpersSrc().split('\n'): yield line def classContentSort(obj): isMethod = lambda x:x and x.isMethod def iterBody(body): group = [] for value in body: if isMethod(value): group.append(value) yield group group = [] else: group.append(value) yield group def sortBody(group): methods = [item for item in group if isMethod(item)] return methods[0].name if methods else -1 grp = list(iterBody(obj.children)) grpsrt = sorted(grp, key=sortBody) obj.children = [item for grp in grpsrt for item in grp] def defaultParams(obj): return iter(obj.parameters) def zopeInterfaceMethodParams(obj): if not obj.parent.isInterface: for param in obj.parameters: yield param else: for index, param in enumerate(obj.parameters): if index != 0 and param['name'] != 'self': yield param normalBases = ('object', ) def defaultBases(obj): return iter(obj.bases or normalBases) def zopeInterfaceBases(obj): return iter(obj.bases or ['zope.interface.Interface']) def implAny(obj): for module in obj.parents(lambda x:x.isModule): for name in obj.bases: if any(module.find(lambda v:v.name == name)): return True def zopeImplementsClassBases(obj): return iter(normalBases) if implAny(obj) else defaultBases(obj) def zopeImplementsClassHead(obj): if implAny(obj): for cls in obj.bases: yield 'zope.interface.implements({})'.format(cls)