makiLogic.py :  » Web-Frameworks » Maki » maki-20030512 » spb » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Web Frameworks » Maki 
Maki » maki 20030512 » spb » makiLogic.py
#!/usr/local/bin/python2.0
# Copyright (c) 2001 Samuel Brauer.  All Rights Reserved.  NO WARRANTY.
# $Revision: 1.28 $
import sys
import time
import traceback
import types
import spb.XmlUtil
import spb.makiExceptions
import xml.sax.saxlib
import xml.sax.saxutils

MAKI_NS = 'http://maki.sourceforge.net/maki'

DEFAULT_KEYSTYLE = "attribute"

def debug(func, msg):
  func("makiLogic: "+msg)

def my_eval(sourcecode, compiledfragment, evalDict):
  try:
    return eval(compiledfragment, evalDict)
  except:
    exc_info = sys.exc_info()
    if(isinstance(exc_info[0], types.ClassType) and issubclass(exc_info[0], spb.makiExceptions.MakiException)): raise
    tb = exc_info[2].tb_next
    lineno = tb.tb_lineno
    raise spb.makiExceptions.MakiLogicError, ["%s: %s" % (str(exc_info[0]), str(exc_info[1])), "at line#%d: %s" % (lineno, sourcecode.split("\n")[lineno-1])], tb

def processAttributeString(s, evalDict):
  """s is a string that may contain "{expressions}" which must be evaluated"""
  if(s == None): return ""
  if(s.find('{') < 0): return s
  out = []
  sourcecode = None
  for c in s:
    if(c == '{'):
      if(sourcecode == None):
        sourcecode = []
      else:
        sourcecode.append(c)
    elif(c == '}'):
      if(sourcecode == None):
        out.append(c)
      else:
        val = "".join(sourcecode)
        if(not val or val[0] == '{'):
          out.append(val)
        else:
          out.append(codeToText(val, evalDict))
        sourcecode = None
    else:
      if(sourcecode != None):
        sourcecode.append(c)
      else:
        out.append(c)
  return "".join(out)


def evaluateCode(sourcecode, evalDict):
  """evaluate a piece of python code, returning an object"""
  logFunc = evalDict.get("MAKILOGIC_log", None)
  if(logFunc):
    debug(logFunc, "evaluateCode input: "+sourcecode)
    timein = time.time()
  compiledfragment = compile(sourcecode, "<string>", "eval")
  if(logFunc):
    debug(logFunc, "compilation time: %8.4f" % (time.time() - timein))
    timein = time.time()
  output = my_eval(sourcecode, compiledfragment, evalDict)
  if(logFunc):
    debug(logFunc, "evaluation time: %8.4f" % (time.time() - timein))
    debug(logFunc, "evaluateCode output: "+repr(output))
  return output

def codeToText(sourcecode, evalDict):
  """evaluate a piece of python code, returning a string coerced from the object"""
  return spb.XmlUtil.objectToText(evaluateCode(sourcecode, evalDict))

def codeToSaxEvents(handler, sourcecode, evalDict):
  """evaluate a piece of python code and write SAX2 events representing the result"""
  return spb.XmlUtil.objectToSaxEvents(handler, evaluateCode(sourcecode, evalDict))


def doLogic(sourcecode, evalDict):
  sourcecode = sourcecode.strip() + "\n"
  logFunc = evalDict.get("MAKILOGIC_log", None)
  if(logFunc):
    debug(logFunc, "doLogic input:")
    lineno = 0
    for line in sourcecode.split("\n"):
      lineno += 1
      logFunc("%4d: %s" % (lineno, line))
    timein = time.time()
  compiledfragment = compile(sourcecode, "<string>", "exec")
  if(logFunc):
    debug(logFunc, "compilation time: %8.4f" % (time.time() - timein))
    timein = time.time()

  my_eval(sourcecode, compiledfragment, evalDict)
  if(logFunc):
    debug(logFunc, "evaluation time: %8.4f" % (time.time() - timein))


def stripPrefix(name):
  idx = name.find(':')
  if(idx > 0): return name[idx+1:]
  return name
        

def getUriAndName(attrs, evalDict):
  """returns a tuple (uri, name)"""
  uri = attrs.get((None, 'uri'), None)
  name = attrs.get((None, 'name'), None)
  if(uri): uri = processAttributeString(uri, evalDict)
  if(name):
    name = processAttributeString(name, evalDict)
    name = stripPrefix(name)
  return (uri, name)

#------------------------------------------------------

class QuitParsingEarly(Exception):
  """Used as a signal that the handler did not parse the entire source."""
  def __init__(self, args=None):
    self.args = args

class ElementInfo:
  def __init__(self, name, attrs, needsFlushFlag=1):
    # most normal elements will need to be flushed (written to output stream)
    # maki elements are the exception
    self.name = name
    self.attrs = {}
    for key in attrs.keys():
      self.attrs[key] = attrs[key]
    self.bufferCharsFlag = 1
    self.chars = ''
    self.needsFlushFlag = needsFlushFlag 


class makiLogicHandler(xml.sax.saxlib.ContentHandler):
  def __init__(self, out, evalDict, maxMakiTags=None):
    self.out = out
    self.prefixMappings = {}
    self.uriMappings = {}
    self.undeclaredPrefixes = []
    self.evalDict = evalDict
    self.elements = [] # one ElementInfo instance per open XML element we parse
    self.makiElements = [] # one ElementInfo instance per open element that was dynamically generated by maki:element
    self.locator = None
    self.maxMakiTags = maxMakiTags
    self.makiTags = 0
    self.quitLine = None
    self.quitColumn = None

  def getQuitLocation(self):
    return (self.quitLine, self.quitColumn)

  def setDocumentLocator(self, locator):
    self.locator = locator

  def writeCharacters(self, chars, escape=0):
    if(not chars): return
    if(isinstance(chars, types.UnicodeType)): chars = chars.encode('utf-8')
    if(escape == 1): self.out.write(xml.sax.saxutils.escape(chars))
    elif(escape == 2): self.out.write(xml.sax.saxutils.escape(chars).replace('"', '&quot;'))
    else: self.out.write(chars)

  def writeStartDocument(self):
    header = '<?xml version="1.0" encoding="utf-8"?>'
    self.out.write(header)

  def writeStartElementNS(self, name, attrs):
    uri = name[0]
    lname = name[1]
    self.out.write('<')
    if(uri):
      self.writeCharacters(self.uriMappings[uri][-1])
      self.out.write(':')
    self.writeCharacters(lname)

    for prefix in self.undeclaredPrefixes:
      self.writeCharacters(' xmlns:%s="%s"' % (prefix, self.prefixMappings[prefix][-1]))
    self.undeclaredPrefixes = []

    for pair in attrs.items():
      attname = pair[0]
      attvalue = pair[1]
      self.out.write(' ')
      atturi = attname[0]
      attlname = attname[1]
      if(atturi):
        prefix = self.uriMappings[atturi][-1]
        self.writeCharacters(prefix)
        self.out.write(':')
      #self.out.write('%s="%s"' % (attlname, xml.sax.saxutils.escape(attvalue)))
      self.writeCharacters('%s="' % attlname)
      self.writeCharacters(attvalue, 2)
      self.out.write('"')
    self.out.write('>')

  def writeEndElementNS(self, name):
    uri = name[0]
    lname = name[1]
    self.out.write('</')
    if(uri):
      self.writeCharacters(self.uriMappings[uri][-1])
      self.out.write(':')
    self.writeCharacters(lname)
    self.out.write('>')

  def writePI(self, target, data):
    #self.out.write('<?%s %s?>' % (target, data))
    self.out.write('<?')
    self.writeCharacters('%s %s' % (target, data))
    self.out.write('?>')

  def writeComment(self, data):
    #self.out.write('<!--%s-->' % data)
    self.out.write('<!--')
    self.writeCharacters(data)
    self.out.write('-->')

  def getHelperHandler(self):
    printhandler = spb.XmlUtil.PrintHandler(self.out, self.prefixMappings, self.uriMappings, self.undeclaredPrefixes)
    return spb.XmlUtil.FilterHandler(printhandler, 0, 0, 0, 1)


  def flush(self):
    idx = 0
    for element in self.elements:
      if(element.needsFlushFlag):
        self.writeStartElementNS(element.name, element.attrs)
        element.needsFlushFlag = 0
        self.writeCharacters(element.chars, 1)
        element.bufferCharsFlag = 0
        element.chars = '' # free some memory
        element.attrs = None # free some memory


  def startDocument(self):
    self.writeStartDocument()

  def startPrefixMapping(self, prefix, uri):
    mappings = self.prefixMappings.get(prefix, [])
    mappings.append(uri)
    self.prefixMappings[prefix] = mappings
    mappings = self.uriMappings.get(uri, [])
    mappings.append(prefix)
    self.uriMappings[uri] = mappings
    if(prefix not in self.undeclaredPrefixes):
      self.undeclaredPrefixes.append(prefix)

  def endPrefixMapping(self, prefix):
    mappings = self.prefixMappings.get(prefix)
    uri = mappings.pop()
    mappings = self.uriMappings.get(uri)
    mappings.pop()

#
# Notes on <maki:element>
# Any directly contained character data is passed straight through. 
# If you want character data to be evaluated, it must be explicitly inside
# a maki:expr.
#
# Notes on <maki:attribute>
# These must be the first children of their enclosing element.
# If they follow any character data or other elements then the behavior
# is undefined (quite possibly a runtime exception).
#

  def startElementNS(self, name, qname, attrs):
    if(name[0] == MAKI_NS):
      if(name[1] != 'attribute'): self.flush()
      if(name[1] != 'element'): self.elements.append(ElementInfo(name, attrs, 0))
      if(name[1] == 'element'):
        (eluri, elname) = getUriAndName(attrs, self.evalDict)
        if(not elname): raise RuntimeError, "maki:element without @name"
        element = ElementInfo((eluri, elname), {}, 1)
        self.elements.append(element)
        self.makiElements.append(element)
      elif(name[1] not in ('page', 'logic', 'global-logic', 'expr', 'attribute', 'processing-instruction', 'comment', 'elements')):
        raise RuntimeError, "Unrecognized maki tag '%s'" % name[1]
    else:
      self.flush()
      self.elements.append(ElementInfo(name, attrs, 1))
      

  def endElementNS(self, name, qname):
    if(name[0] == MAKI_NS):
      self.makiTags += 1
      if(name[1] == 'element'): self.flush()
      element = self.elements.pop()

      if(name[1] == 'page'):
        pass
      elif(name[1] == 'logic'):
        doLogic(element.chars, self.evalDict)
      elif(name[1] == 'expr'):
        result = evaluateCode(element.chars.strip(), self.evalDict)
        if(result != None):
          (eluri, elname) = getUriAndName(element.attrs, self.evalDict)
          # if a @name exists, wrap the expression with an element
          if(elname): self.writeStartElementNS((eluri, elname), {})
  
          keyStyle = element.attrs.get((None, 'keyStyle'), None)
          if(keyStyle):
            if(keyStyle not in ('element', 'attribute')): raise RuntimeError, "@keyStyle must be 'element' or 'attribute'"
          else:
            keyStyle = DEFAULT_KEYSTYLE
          spb.XmlUtil.objectToSaxEvents(self, result, keyStyle)
          if(elname): self.writeEndElementNS((eluri, elname))
      elif(name[1] == 'elements'):
        (eluri, elname) = getUriAndName(element.attrs, self.evalDict)
        if(not elname): raise RuntimeError, "maki:elements without @name"
        objects = evaluateCode(element.chars.strip(), self.evalDict)
        if(objects):
          keyStyle = element.attrs.get((None, 'keyStyle'), None)
          if(keyStyle):
            if(keyStyle not in ('element', 'attribute')): raise RuntimeError, "@keyStyle must be 'element' or 'attribute'"
          else:
            keyStyle = DEFAULT_KEYSTYLE
          for object in objects:
            self.writeStartElementNS((eluri, elname), {})
            spb.XmlUtil.objectToSaxEvents(self, object, keyStyle)
            self.writeEndElementNS((eluri, elname))
      elif(name[1] == 'element'):
        self.makiElements.pop()
        self.writeEndElementNS(element.name)
      elif(name[1] == 'attribute'):
        (atturi, attname) = getUriAndName(element.attrs, self.evalDict)
        if(not attname): raise RuntimeError, "maki:attribute without @name"
        attvalue = codeToText(element.chars, self.evalDict)
        targetElement = self.elements[-1]
        targetElement.attrs[(atturi, attname)] = attvalue
      elif(name[1] == 'processing-instruction'):
        piname = element.attrs.get((None, 'name'), None)
        target = processAttributeString(piname, self.evalDict)
        if(not target): raise RuntimeError, "<processing-instruction> without @name"
        data = codeToText(element.chars, self.evalDict)
        self.writePI(target, data)
      elif(name[1] == 'comment'):
        comment = codeToText(element.chars, self.evalDict)
        self.writeComment(comment)
      else:
        raise RuntimeError, "Unrecognized maki tag '%s'" % name[1]
      if(self.maxMakiTags != None and self.makiTags >= self.maxMakiTags):
        self.quitLine = self.locator.getLineNumber()
        self.quitColumn = self.locator.getColumnNumber()
        raise QuitParsingEarly
    else:
      self.flush()
      self.elements.pop()
      self.writeEndElementNS(name)


  def startElement(self, name, attrs):
    nsattrs = {}
    for key in attrs.keys():
      nsattrs[(None, key)] = attrs[key]
    self.startElementNS((None, name), name, nsattrs)

  def endElement(self, name):
    self.endElementNS((None, name), name)
      

  def characters(self, content):
    if(not content): return
    element = self.elements[-1]
    if(element.bufferCharsFlag):
      element.chars += content
      if(element.needsFlushFlag):
        # may need to flush
        if(content.strip()):
          self.flush()
    else:
      self.writeCharacters(content, 1)


  def ignorableWhitespace(self, content):
    self.characters(content)

  def processingInstruction(self, target, data):
    self.flush()
    self.writePI(target, data)

#------------------------------------------------------

def process(s, out, evalDict):
  # count number of maki start tags in s
  makiTags = s.count("<maki:")
  handler = makiLogicHandler(out, evalDict, makiTags)
  try:
    spb.XmlUtil.parseString(s, handler, 1)
  except QuitParsingEarly:
    (lineno, columnno) = handler.getQuitLocation()
    lines = s.split('\n')
    line = lines[lineno-1]
    idx = line.find('>', columnno) + 1
    out.write(line[idx:])
    out.write('\n')
    for line in lines[lineno:]:
      out.write(line)
      out.write('\n')
    

    
def main():
  needClose = 0
  if(len(sys.argv) < 2):
    input = sys.stdin
  else:
    input = open(sys.argv[1])
    needClose = 1
  #handler = makiLogicHandler(sys.stdout, {}, {})
  #spb.XmlUtil.parseStream(input, handler, 1)
  process(input.read(), sys.stdout, {})
  if(needClose): input.close()


if __name__ == "__main__":
  main()
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.