dynamic.py :  » Database » Modeling-Framework » Modeling-0.9 » Modeling » 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 » dynamic.py
#! /usr/bin/env python
# -*- 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.
#-----------------------------------------------------------------------------
"""
Documentation not written yet --see doc/README.dynamic.txt for details.
"""
import code, new, sys

from Modeling.CustomObject import CustomObject
from Modeling.ModelSet import defaultModelSet
from Modeling.utils import capitalizeFirstLetter

def function_for_code(c, func_name):
  c+='\nfunc='+func_name+'\n'
  exec(c)
  return func

def instance_method(aClass, c, func_name):
  func=function_for_code(c, func_name)
  meth=new.instancemethod(func, None, aClass)
  return meth

def init_code(entity, init=None):
  """
  init: the original __init__, if available
  """
  c="def __init__(self, **kw):\n"
  for p in entity.classProperties():
    c+="  self._"+p.name()+"="
    if hasattr(p,'isToMany'): # rel
      if p.isToMany():
        c+="()"
      else:
        c+="None"
    else:
      c+=repr(p.defaultValue())
    c+="\n"
  c+="""  for k,v in kw.items():
    self.takeValueForKey(v, k)
  """
  if init:
    c+="  apply(self.%s, (), kw)"%init
  return c

def add_init(aClass, entity):
  "Adds to the class the method __init__() suitable for entity"
  c=init_code(entity)
  m=instance_method(aClass, c, "__init__")
  setattr(aClass,'__init__',m)

def define_entityName(aClass, entity):
  c="""def entityName(self):
      "Used by the framework to link this object to its entity"
      return "%s" # do not change
      """%entity.name()
  return c

def add_entityName(aClass, entity):
  "Adds to the new class the method entityName() suitable for entity"
  c=define_entityName(aClass, entity)
  m=instance_method(aClass, c, "entityName")
  setattr(aClass,'entityName',m)

def add_getters(aClass, entity):
  "Adds getters to aClass, one for each entity.classProperties()"
  for p in entity.classProperties():
    add_getter(aClass, p)

def add_setters(aClass, entity):
  "Adds setters to aClass, one for each entity.classProperties()"
  for p in entity.classProperties():
    add_setter(aClass, p)

def getter_code(prop):
  func_name="get"+capitalizeFirstLetter(prop.name())
  c='def %s(self):\n  self.willRead()\n'%func_name
  c+="  return self._"+prop.name()
  return func_name, c

def add_getter(aClass, prop): 
  "Builds and adds to aClass the getter for property prop"
  func_name, c=getter_code(prop)
  m=instance_method(aClass, c, func_name)
  setattr(aClass, m.__name__, m)

def setters_code(prop):
  "returns: ( (name, code_string), ... )"
  names_n_funcs=[]
  part_func_name=capitalizeFirstLetter(prop.name())
  if hasattr(prop,'isToMany') and prop.isToMany():
    func_name="addTo"+part_func_name
    c='''def %(func_name)s(self, obj):
    if obj not in self._%(name)s:
      self.willChange()
      _list=list(self._%(name)s)
      _list.append(obj)
      self._%(name)s=tuple(_list)
    '''%{'func_name': func_name, 'name': prop.name()}
    names_n_funcs.append( (func_name, c) )
      
    func_name="removeFrom"+part_func_name
    c='''def %(func_name)s(self, obj):
    self.willChange()
    _list=list(self._%(name)s)
    _list.remove(obj)
    self._%(name)s=tuple(_list)
    '''%{'func_name': func_name, 'name': prop.name()}
    names_n_funcs.append( (func_name, c) )
    
  func_name="set"+part_func_name
  c='def %s(self, obj):\n  self.willChange()\n'%func_name
  c+="  self._"+prop.name()+"=obj"
  names_n_funcs.append( (func_name, c) )
  return names_n_funcs

def add_setter(aClass, prop):
  "Builds and adds to aClass the setter for property prop"
  names_n_funcs=setters_code(prop)
  for func_name, c in names_n_funcs:
    m=instance_method(aClass, c, func_name)
    setattr(aClass, m.__name__, m)

def add_properties(aClass, entity):
  for p in entity.classProperties():
    #print 'defining prop: ', p.name()
    part_func_name=capitalizeFirstLetter(p.name())
    prop=property(getattr(aClass, 'get'+part_func_name),
                  getattr(aClass, 'set'+part_func_name), None)
    setattr(aClass, p.name(), prop)
    
def build(model, define_properties=0):
  """
  Takes a model and builds the corresponding package and modules

    :Parameters:

      - `model`: either a `Modeling.Model.Model` or a
        `Modeling.PyModel.Model`.  Please note that if it is a pymodel, its
        method build() is called 

      - `define_properties`: 

  """
  from Modeling import PyModel
  if isinstance(model, PyModel.Model):
    if not model.is_built:
      model.build()
    model=model.component
  module_name=model.packageName()
  classes={}
  modules={}
  for e in model.entities():
    c=new.classobj(e.name(), (CustomObject,), {})
    m=new.module(e.name())
    setattr(m, e.name(),c)
    classes[e.name()]=c
    modules[e.name()]=m
    m.__name__= module_name+'.'+e.name()
    add_init(c, e)
    add_entityName(c, e)
    add_getters(c, e)
    add_setters(c, e)
    if define_properties:
      add_properties(c, e)
    c.__module__=module_name+'.'+e.name()
  
  p=new.module(module_name)
  #m.Book=classes['Book']
  import sys
  for name,m in modules.items():
    setattr(p,name,m)
  sys.modules[module_name]=p
  
  # the following is needed if we want to "from AB.Book import Book"
  for name,m in modules.items():
    sys.modules[module_name+'.'+name]=m


##
## Examples of use follow
##
if __name__ == "__main__":
  from Modeling import ModelSet,Model
  model_name="AuthorBooks"
  if ModelSet.defaultModelSet().modelNamed(model_name) is None:
    import os
    model=Model.searchModel(model_name, 'xmlmodels', verbose=1)
    
    if not model:
      raise RuntimeError, "Couldn't load model '%s'"%model_name
    else:
      ModelSet.defaultModelSet().addModel(model)

  build(model)
  from Modeling.EditingContext import EditingContext
  ec=EditingContext()
  print [b.getTitle() for b in ec.fetch('Book')]
  from AuthorBooks import Book
  from AuthorBooks.Book import Book
  print Book
  b=Book(title='mon titre')
  print repr(b.getTitle())
  sys.exit(0)

########################################################################
# metaclass
#
def info(classdict, msg):
  if classdict.get('mdl_verbose_metaclass', None):
    sys.stderr.write("[CustomObjectMeta] "+msg+'\n')
    
def checkEntityName(classname, bases, classdict):
  entityName=classdict.get('entityName', None)
  if entityName is None:
    info(classdict, 'entityName is not present: searching base classes')
    for b in bases:
      if b==CustomObject:
        continue;
      entityName=getattr(b, 'entityName',None)
      if entityName:
        info(classdict, 'Found in %s'%b.__name__)

  if entityName is None:
    info(classdict, 'entityName is not present: using default: %s'%classname)
    entityName=classname
  if not callable(entityName):
    classdict['entityName']=lambda self, n=entityName: n
  else:
    entityName=entityName.im_func(None)
  return entityName

def addCustomObject(bases):
  from Modeling.CustomObject import CustomObject
  if CustomObject not in bases:
    bases=list(bases)
    bases.append(CustomObject)
    bases=tuple(bases)
  return bases

def check_oldinit(classname, oldinit, entity):
  "Check that the already defined __init__ can be called without any arguments"
  import inspect
  args, varargs, varkw, defaults=inspect.getargspec(oldinit)
  if len(args)-len(defaults)>1:
    raise RuntimeError,'%s.__init__() cannot be called without arguments'%classname
  # to be continued: on veut pouvoir appeler init() avec les bons arguments,
  # tout en rcuprant ceux qui peuvent nous servir (les attributs)
  # e.g. init(self, attr1='t') ou init(self, attr1='x', non_attr='xx') etc.

def define_init(entity, classname, classdict):
  oldinit=classdict.get('__init__', None)
  if oldinit:
    classdict['__original_init__']=oldinit
    check_oldinit(classname, oldinit, entity)
  c=init_code(entity, oldinit)

  init=function_for_code(c, '__init__')
  classdict['__init__']=init

def define_getter(prop, classdict):
  func_name, c=getter_code(prop)
  info(classdict, "adding getter: %s"%func_name)
  getter=function_for_code(c, func_name)
  classdict[func_name]=getter

def define_getters(entity, classname, classdict):
  info(classdict, "setting getters")
  for p in entity.classProperties():
    define_getter(p, classdict)
    
def define_setter(prop, classdict):
  names_and_funcs=setters_code(prop)
  for func_name, c in names_and_funcs:
    info(classdict, "adding setter: %s"%func_name)
    setter=function_for_code(c, func_name)
    classdict[func_name]=setter

def define_setters(entity, classname, classdict):
  info(classdict, "setting setters")
  for p in entity.classProperties():
    define_setter(p, classdict)

def define_properties(entity, classname, classdict):
  #info(classdict, "defining properties for class %s"%classname)
  for p in entity.classProperties():
    info(classdict, "adding properties '%s' for class %s"%(p.name(),classname))
    part_func_name=capitalizeFirstLetter(p.name())
    prop=property(classdict['get'+part_func_name],
                  classdict['set'+part_func_name], None)
    classdict[p.name()]=prop
    
try:
  class A(type): pass
  metaclass_available=1
  del A
except TypeError:
  metaclass_available=0

class EntityNotFound(RuntimeError): pass

if metaclass_available:
  class CustomObjectMeta(type):
      def __new__(meta,classname,bases,classdict):
        info(classdict, 'meta: %s'%meta)
        info(classdict, 'classname: '+classname)
        info(classdict, 'bases: %s'%(bases,))
        info(classdict, 'classdict: %s'%classdict)
  
        entityName=checkEntityName(classname, bases, classdict)
        bases=addCustomObject(bases)
        from Modeling.ModelSet import defaultModelSet
        entity=defaultModelSet().entityNamed(entityName)
        if entity is None:
          raise EntityNotFound, 'Unable to initialize class %s: entity %s not found'%(classname, entityName)
        else:
          define_init(entity, classname, classdict)
          define_getters(entity, classname, classdict)
          define_setters(entity, classname, classdict)
          if classdict.get('mdl_define_properties', None):
            define_properties(entity, classname, classdict)
        return super(CustomObjectMeta,meta).__new__(meta,classname,
                                                    bases,classdict)
  
  
  def build_with_metaclass(model, define_properties=0, verbose=0):
    module_name=model.packageName()
    classes={}
    modules={}
    for e in model.entities():
      c=CustomObjectMeta(e.className(), (),
                         {'mdl_verbose_metaclass': verbose,
                          'mdl_define_properties': define_properties})
      m=new.module(e.name())
      setattr(m, e.name(),c)
      classes[e.name()]=c
      modules[e.name()]=m
      m.__name__=model.packageName()+'.'+e.name() # pas requis? mais conforme
      
    p=new.module(module_name)
    #m.Book=classes['Book']
    import sys
    for name,m in modules.items():
      setattr(p,name,m)
    sys.modules[module_name]=p
    
    # the following is needed if we want to "from AuthorBooks.Book import Book"
    for name,m in modules.items():
      sys.modules[module_name+'.'+name]=m
else:
  def build_with_metaclass(model, define_properties=0, verbose=0):
    raise NotImplementedError, "metaclass are not available"
  

##
## Two examples of use follow
##
if __name__ == "__main__2":
  from Modeling import ModelSet,Model
  model_name="AuthorBooks"
  if ModelSet.defaultModelSet().modelNamed(model_name) is None:
    import os
    mydir = '.'
    model=Model.searchModel(model_name, mydir, verbose=1)
    
    if not model:
      raise RuntimeError, "Couldn't load model '%s'"%model_name
    else:
      ModelSet.defaultModelSet().addModel(model)
  
  class Book:
    __metaclass__=CustomObjectMeta
    mdl_verbose_metaclass=1
    mdl_define_properties=1
    entityName='Book'
    #def entityName(self):
    #  return 'Book'
    #def __init__(self):
    #  print 'PPP'
    def willRead(self):
      print '[willRead]',
    def willChange(self):
      print '[willChange]',
    def _getTitle(self):
      print '[_getTitle()]',
      return self._title
    def _setTitle(self, title):
      print '[_setTitle()]',
      self._title=title
  #__metaclass__=CustomObjectMeta
  #c=type('Writer', (), {'__metaclass__': CustomObjectMeta,
  #                      'mdl_verbose_metaclass': 1,
  #                      'mdl_define_properties': 1})
  Writer=CustomObjectMeta('Writer', (), {'mdl_verbose_metaclass': 1,
                                         'mdl_define_properties': 0})
  #Book=CustomObjectMeta('Book', (), {'mdl_verbose_metaclass': 1})
  print Writer, Writer.__bases__
  
  from Modeling.EditingContext import EditingContext
  ec=EditingContext()
  print Book.__bases__
  b=Book(title='glop')
  ec.insert(b)
  print b.entityName()
  print b._title
  b.setTitle('title test')
  print b.getTitle()
  print ec.allInsertedObjects(), b
  print 'trying properties'
  print b.title
  print '## KVC'
  print 'storedValue ',b.storedValueForKey('title')
  print 'takestored  ',b.takeStoredValueForKey('takeStoredValueForKey','title')
  print 'value       ',b.valueForKey('title')
  print 'takeValue   ',b.takeValueForKey('takeStoredValueForKey','title')
  print 'title: ', b.title
  sys.exit(0)
  
if __name__ == "__main__":
  from Modeling import ModelSet,Model
  model_name="AuthorBooks"
  if ModelSet.defaultModelSet().modelNamed(model_name) is None:
    import os
    mydir = '.'
    model=Model.searchModel(model_name, mydir, verbose=1)
    
    if not model:
      raise RuntimeError, "Couldn't load model '%s'"%model_name
    else:
      ModelSet.defaultModelSet().addModel(model)
  
  build_with_metaclass(model, define_properties=0)
  from Modeling.EditingContext import EditingContext
  ec=EditingContext()
  print [b.getTitle() for b in ec.fetch('Book')]
  from AuthorBooks import Book
  from AuthorBooks.Book import Book
  print Book
  b=Book(title='mon titre')
  print repr(b.getTitle()), b.title
  sys.exit(0)
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.