Logo Search packages:      
Sourcecode: python-biopython version File versions  Download package

sourcegen.py

#!/usr/bin/python

"""
This module can be used to generate python source code. It has an interface
similar to the "new" module.

"""

import sys, os
import string

BANGLINE = "#!/usr/bin/python\n"

def _tuplestr(tup):
      return string.join(map(str, tup), ", ")

# These functions resembled the "new" module interface, but with different
# names. This is the function interface. There are also generator object
# interfaces below.

def genClass(klassname, parents, attribs=None, doc=None, methods=None):
      """genClass(name, parents, [attribs, [doc, [methods]]])
      Return a string of Python source code defineing a class object.
      Where:
            name = class name (string)
            parents = tuple of parent class objects or strings.
            attribs = class-global attributes to define, contained in a dictionary.
            doc = a doc string (optional)
            methods = list of methods strings.
      """
      s = []
      if parents:
            s.append( "class %s(%s):" % (klassname, _tuplestr(parents)) )
      else:
            s.append( "class %s:" % (klassname) )
      if doc:
            s.append('\t"""%s"""' % doc)
      if attribs:
            for key, val in attribs.items():
                  s.append( "\t%s = %r" % (key, val) )
      if methods is not None:
            s.extend(map(str, list(methods)))
      if len(s) == 1:
            s.append("\tpass")
      s.append("\n")
      return string.join(s, "\n")

def genFunc(funcname, params, body=None, globals=None, doc=None):
      s = []
      s.append( "def %s(%s):" % (funcname, _tuplestr(params)) )
      if doc:
            s.append('\t"""%s"""' % doc)
      if globals is not None:
            s.append("\tglobal %s" % _tuplestr(globals))
      if body is None:
            s.append("\tpass")
      else:
            s.append(body)
      s.append("\n")
      return string.join(s, "\n")

def genMethod(funcname, params, body=None, globals=None, doc=None):
      s = []
      s.append( "def %s(self, %s):" % (funcname, _tuplestr(params)) )
      if doc:
            s.append('\t"""%s"""' % doc)
      if globals is not None:
            s.append("\tglobal %s" % _tuplestr(globals))
      if body is None:
            s.append("\tpass")
      elif type(body) is str:
            s.extend( map(lambda l: "\t%s"%l, string.split(body, "\n")) )
      elif type(body) is list or type(body) is tuple:
            s.extend( map(lambda l: "\t%s"%l, body) )
      else:
            raise TypeError, "invalid type for body text"
      s.append("\n")
      # insert a tab in the front of each line and return lines joined with newlines.
      return string.join(map(lambda l: "\t%s"%l, s), "\n")

def genComment(text):
      lines = text.split("\n")
      lines = map(lambda l: "# %s" % l, lines)
      return string.join(lines, "\n")

def genImport(module, obj=None, indent=0):
      if type(module) is type(sys): # a module type
            module = module.__name__
      if obj:
            if type(obj) is tuple or type(obj) is list:
                  obj = _tuplestr(obj)
            return "%sfrom %s import %s\n" % ("\t"*indent, module, obj)
      else:
            return "%simport %s\n" % ("\t"*indent, module)


# a Python source producer object
00098 class SourceGen:
      """SourceGen(outfile, [bangline])
An instance of this SourceGen class is a factory for generating python
source code, by writing to a file object.

      """
      def __init__(self, outfile, bangline=None):
            self.outfile = outfile
            bangline = bangline or BANGLINE     
            self.outfile.write(bangline)

      def genClass(self, klassname, parents=None, attribs=None, doc=None, methods=None):
            self.outfile.write( genClass(klassname, parents, attribs, doc, methods) )

      def genFunc(self, funcname, params, attribs=None, doc=None):
            self.outfile.write( genFunc(funcname, params, attribs, doc) )

      def genMethod(self, funcname, params, body=None, globals=None, doc=None):
            self.outfile.write( genMethod(funcname, params, body, globals, doc) )

      def genComment(self, text):
            self.outfile.write( genComment(text) )

      def genImport(self, module, obj=None):
            self.outfile.write( genImport(module, obj) )

      def genBlank(self):
            self.outfile.write("\n")

      def write(self, obj):
            self.outfile.write( str(obj) )

      def writeln(self, obj):
            self.write(obj)
            self.write("\n")


# factory functions. 
# Returns a source generator ready to write to a file (or filename).
def get_generator(outfile):
      if type(outfile) is str:
            outfile = open(outfile, "w")
      return SourceGen(outfile)

# return a SourceFile object.
def get_sourcefile(outfile=None, bangline=None):
      if type(outfile) is str:
            outfile = open(outfile, "w")
      return SourceFile(outfile, bangline)


# object holder interface
class FunctionHolder:
      def __init__(self, funcname, params=None, attributes=None, doc=None):
            self.name = funcname
            self.params = params or ()
            self.attributes = attributes or {}
            self.doc = doc
      def __str__(self):
            return genFunc(self.name, self.params, self.attributes, self.doc)
      def add_attribute(self, name, value):
            self.attributes[name] = value
      set_attribute = add_attribute
      def get_attribute(self, name):
            return self.attributes[name]
      def del_attribute(self, name):
            del self.attributes[name]


class MethodHolder:
      def __init__(self, funcname, params=None, body=None, globals=None, doc=None):
            self.name = funcname
            self.params = params or ()
            self.body = body
            self.globals = globals
            self.doc = doc

      def __str__(self):
            return genMethod(self.name, self.params, self.body, self.globals, self.doc)


class ClassHolder:
      def __init__(self, klassname, parents=None, attributes=None, doc=None, methods=None):
            self.classname = klassname
            self.parents = parents or ()
            self.attributes = attributes or {}
            self.methods = methods or []
            self.doc = doc
      def __str__(self):
            return genClass(self.classname, self.parents, self.attributes, self.doc, self.methods)

      def add_method(self, funcname, params, body=None, globals=None, doc=None):
            mh = MethodHolder(funcname, params, body, globals, doc)
            self.methods.append(mh)
            return mh

      def add_attribute(self, name, value):
            self.attributes[name] = value
      set_attribute = add_attribute
      def get_attribute(self, name):
            return self.attributes[name]
      def del_attribute(self, name):
            del self.attributes[name]


# this is only good for small file generation
class SourceFile:
      def __init__(self, fo=None, bangline=None):
            print "Writing to", fo
            self.fo = fo
            self.elements = []
            self.docstring = None
            self.bangline = bangline or BANGLINE
      def __str__(self):
            s = [self.bangline]
            if self.docstring:
                  s.append('"""\n%s\n"""\n\n' % (self.docstring))
            s.extend(map(str, self.elements))
            return "\n".join(s)

      def add_doc(self, docstring):
            self.docstring = docstring
      def add_comment(self, text):
            self.elements.append(genComment(text))
      def add_import(self, module, obj=None):
            self.elements.append(genImport(module, obj))
      def add_blank(self):
            self.elements.append("\n")

      def add_function(self, funcname, params, attribs=None, doc=None):
            fh = FunctionHolder(funcname, params, attribs, doc)
            self.elements.append(fh)
            return fh

      def add_class(self, klassname, parents, attributes=None, doc=None, methods=None):
            ch = ClassHolder(klassname, parents, attributes, doc, methods)
            self.elements.append(ch)
            return ch

      def append(self, holder):
            self.elements.append(holder)

      def write(self, fo=None):
            fo = fo or self.fo
            fo.write(str(self))
      def writefile(self, filename=None):
            filename = filename or self.filename
            if filename:
                  fo = open(filename, "w")
                  self.write(fo)
            else:
                  raise ValueError, "SourceFile: no filename given to write to!"



if __name__ == "__main__":
      class SUBCLASS:
            pass
      print "generated classes"
      print "-----------------"
      print genComment(__doc__)
      print genClass("test1", (), {})
      print genClass("test2", ("sub1",), {})
      print genClass("test3", ("sub1","sub2"), {})
      print genClass("test4", (SUBCLASS,), {})
      print genClass("test5", (), {"attr1": 1})
      print genClass("test6", (), {}, "One docstring")
      print genClass("test7", (), {"attr1": 1}, "another docstring")

      print "Holder classes"
      print "--------------"
      print genImport(sys.modules[__name__])
      print genImport(sys)
      print genImport(sys, "open")
      ch = ClassHolder("holdclass", ("sub1",))
      print ch
      print "--------------"
      ch.add_method("holdmethod1", ("param1",))
      print ch
      print "--------------"
      ch.add_method("holdmethod2", ("hm2p1",), "print 'body code'", doc="Some docstring")
      print ch
      print "--------------"
      ch.doc = "Documentation for holdclass."
      print ch
      print "--------------"
      sf = SourceFile()
      sf.add_doc("Testing the generator.")
      sf.add_import(sys)
      sf.append(ch)
      sf.write(sys.stdout)


Generated by  Doxygen 1.6.0   Back to index