ModelMason.py :  » Database » Modeling-Framework » Modeling-0.9 » Modeling » ModelMasons » 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 » Database » Modeling Framework 
Modeling Framework » Modeling 0.9 » Modeling » ModelMasons » ModelMason.py
# -*- coding: iso-8859-1 -*-
#-----------------------------------------------------------------------------
# Modeling Framework: an Object-Relational Bridge for python
#
# Copyright (c) 2001-2004 Sbastien Bigaret <sbigaret@users.sourceforge.net>
# All rights reserved.
#
# This file is part of the Modeling Framework.
#
# This code is distributed under a "3-clause BSD"-style license;
# see the LICENSE file for details.
#-----------------------------------------------------------------------------


"""

ModelMason contains the base class for every ''mason'' and is of no interest
except if you plan to design a new module to generate code/files from a Model.

When this is the case, the class' documentation indicate the rules that should
be respected to ensure easy integration with the framework's tools such as the
script mdl_generate_python_code or the ZModeler.

  CVS information

    $Id: ModelMason.py 974 2006-02-26 14:06:07Z sbigaret $
  
"""
__version__='$Revision: 974 $'[11:-2]

import time, os, string, sys

from Cheetah.Template import Template

class ModelMason:
  """
  This class should be the base class for every masons.

  When subclassing this class, you should take care of:

    - call ModelMason.__init__() if it is overridden

    - if the subclass needs to change/create sth. on the filesystem, it *must*
      check whether 'fake_mode' is set: if it is set, absolutely no changes
      should be made on the disk.

      Methods createEmptyFile(), createFileFromTemplate(), copyFile() and
      build_package() can be used without this precaution since they already
      check 'self.fake_mode' before making any changes on the disk.

    - call log() to record any action relative to the generation (such as the
      creation of a file). Please note that you should be ready to log these
      actions even when fake_mode is set. For example, suppose 'file.py'
      should be generated but not overwritten; if the file does not exist
      you'd log('Creating file file.py'), and if it exists you'd log('File.py
      exists, skipping') whether fake_mode is set or not.  This makes it
      possible for the user to see what would happen whene (re)generating the
      code without actually making the changes.

  Following these rules makes it easy to integrate a custom ''mason'' into
  the script mdl_generate_python_code and the ZModeler.
  
  All subclasses need to override build() and put there the logic which
  generates the code. You will probably override method tmpl_namespace() as
  well (see its documentation for details).

  You can also refer to PyModelMason for an example of use.
    
  """
  
  def __init__(self, model, rootPath, concreteBuilder, bricksDir,
               verbose_mode=0, fake_mode=0):
    """
    Initializes the ModelMason so that the built files are based on the
    supplied model.

    Parameters:

      model -- the model from which the generated python package should be
        generated
      
      rootPath -- path of a directory where the corresponding package should
        be dropped
      
      concreteBuilder -- the module containing the concrete builder
      
      bricksDir -- path for the directory containing the templates, relative
        to the path where the module of 'concreteBuilder' is stored
      
      verbose_mode -- whether logging is activated or not, see log(). When
        true, the building process logs some informations in sys.stderr while
        generating the files

      fake_mode -- if true, do not create or change any file, just report what
        would be done

    Subclasses may decide to supply a default value for the product's base
    directory when parameter 'rootPath' is not supplied.
    """
    self.model = model
    self.rootPath=rootPath
    packagePathList=[rootPath]
    packagePathList.extend(string.split(self.model.packageName(), '.'))
    self.packagePath = apply(os.path.join, packagePathList)
    self.bricksPath=os.path.join(os.path.dirname(concreteBuilder.__file__),
                                 bricksDir)
    self.verbose_mode=verbose_mode
    self.fake_mode=fake_mode
    
  def fullPathForBrick(self, aBrick):
    """
    Returns the full path for a given brick's filename.
    This is the preferred way for accessing bricks
    """
    return os.path.join(self.bricksPath(), aBrick)
  
  def fullPathForGeneratedFile(self, filename):
    "Returns the full path for a given generated filename."
    return os.path.join(self.packagePath, filename)
  
  def createEmptyFile(self,filename,overwrite=0):
    """
    Create the empty file 'filename' ; the filename is a relative path
    (relative to 'self.productBaseDirectory()')
    """
    if not os.path.isabs(filename):
      filename=self.fullPathForGeneratedFile(filename)
    if not overwrite and os.path.exists(filename):
      self.log('File %s exists, skipping\n'%filename)
      return
    self.log('Creating empty file %s\n'%filename)
    if not self.fake_mode:
      f = open(filename,"w")
      f.close()

  def copyFile(self, templateFilename, destinationFilename,overwrite=0):
    """
    Copy the template file to the destination file, unchanged. Both filenames
    should be relative to, respectively, bricksBaseDirectory and
    productBaseDirectory.
    """
    if not os.path.isabs(filename):
      filename=self.fullPathForGeneratedFile(filename)
    if not overwrite and os.path.exists(filename):
      self.log('File %s exists, skipping\n'%filename)
      return
    self.log('Creating file %s\n'%destinationFilename)
    if not self.fake_mode:
      _f1 = open(self.fullPathForGeneratedFile(destinationFilename),'w')
      _f2 = open(self.fullPathForBrick(templateFilename),'r')
      _f1.write(_f2.read())
      _f1.close()
      _f2.close()

  _marker=[]
  def templateObjectForTemplate(self, template, namespace=_marker):
    """
    Initializes a Template object from the supplied templateFile. Overrides
    this to perform any additional initializations for Templates, such as
    building a namespace for the template.

    Parameters:

      template -- a Cheetah.Template object
      
      namespace -- the template will use that namespace. If ommitted, it
        defaults to self.tmpl_namespace()
      
    Default implementation simply returns the Template object
    """
    if namespace is self._marker: namespace=self.tmpl_namespace()
    namespace=self.fix_tmpl_namespace(namespace)
    #for dict in namespace:
    for key in namespace.keys():
      setattr(template, key, namespace[key])
    return template


  def createFileFromTemplate(self, template, destFile, namespace=_marker,
                             overwrite=0):
    """
    Parameters:

      template -- a Cheetah.Template object
      
      namespace -- the template will use that namespace. If ommitted, it
        defaults to self.tmpl_namespace()
      
      destFile -- the destination file path, relative to productBaseDirectory

    """
    if namespace is self._marker: namespace=self.tmpl_namespace()
    namespace=self.fix_tmpl_namespace(namespace)
    destFile = self.fullPathForGeneratedFile(destFile)
    file_exists=os.path.exists(destFile)
    if not overwrite and file_exists:
      self.log("File %s exists, skipping\n"%destFile)
      return
    if not overwrite or (overwrite and not file_exists):
      self.log("Generating %s" % destFile)
    else:
      self.log("Overwriting %s" % destFile)

    if not self.fake_mode:
      f = open(destFile,'w')
      f.write("%s"%self.templateObjectForTemplate(template,namespace=namespace))
      self.log("... done")
    self.log('\n')

  def build(self):
    """
    Build the product ; override it to match your need. Base implementation
    does nothing.
    """
    pass


  def fix_tmpl_namespace(self, namespace):
    """
    Internally used to make any values in the namespace callable --if a value
    is an instance or a python object, it is by a lambda function returning
    the value. We make this because Cheetah sometimes requires a callable.
    """
    # builtin callable() does not work on instances derived from
    # ZODB.Persistent, we use that one instead
    def _callable(o):
      if hasattr(o,'__class__'): return hasattr(o,'__call__')
      return callable(o)
    d={}
    for k,v in namespace.items():
      if _callable(v): d[k]=v
      else: d[k]=lambda p=v: p
    return d
    
  def tmpl_namespace(self):
    """
    This method returns a dictionary used by templates to search for specific
    values.

    Default implementation returns::

      {'model': self.model}
      
    Subclasses override this method to provide their own namespace. This
    namespace is the default one transmitted to the Cheetah template when no
    specific namespace is passed to method createFileFromTemplate().
    """
    return {'model': self.model}
  
  def build_package(self):
    """
    Creates all the necessary directories for the package, which can be
    something like A.B.C.MyPackage.  Creates an empty '__init__.py' in each
    sub-directories if needed: existing __init__.py are not overwritten.
    """
    currentPath=self.rootPath
    packList=[]
    for pack in string.split(self.model.packageName(), '.')[:-1]:
      currentPath=os.path.join(currentPath, pack)
      self.log('Creating directory %s'%currentPath)
      if not self.fake_mode:
        try:
          os.mkdir(currentPath)
        except: self.log('... no')
        else:   self.log('... ok')
      self.log('\n')

      init=os.path.join(currentPath, '__init__.py')
      if os.path.exists(init):
        self.log('%s exists, skipping\n'%init)
      else:
        self.log('Creating %s\n'%init)
        if not self.fake_mode:
          f=open(init,'w') ; f.close()

    # Last, create self.packagePath
    self.log('Creating directory %s'%self.packagePath)
    if not self.fake_mode:
      try:
          os.mkdir(self.packagePath)
      except: self.log('... no')
      else:   self.log('... ok')
    self.log('\n')

  def log(self, msg):
    "Logs the msg to stderr if self.verbose_mode is true"
    if self.verbose_mode:
      sys.stderr.write(msg)
    

  def entitiesSet(self):
    """
    Returns a list of list of entities, where Entities in the same list share
    the same 'moduleName'
    """
    d={}
    for entity in self.model.entities():
      moduleName=entity.moduleName()
      if d.get(moduleName):
        d[moduleName].append(entity)
      else: d[moduleName]=[entity]

    return d.values()

www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.