[migration] when adding a core meta-relation, it should be added to all entities *in the persistent schema*, not only those in the fs schema
"""extends yams to be able to load google appengine's schemasMISSING FEATURES: - ListProperty, StringList, EmailProperty, etc. (XXX) - ReferenceProperty.verbose_name, collection_name, etc. (XXX)XXX proprify this knowing we'll use goa.db:organization: Logilab:copyright: 2008-2009 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2.:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses"""fromos.pathimportjoinfromdatetimeimportdatetime,date,timefromgoogle.appengine.extimportdbfromgoogle.appengine.apiimportdatastore_typesfromyams.buildobjsimport(String,Int,Float,Boolean,Date,Time,Datetime,Bytes,SubjectRelation)fromyams.buildobjsimportmetadefinition,EntityTypefromcubicweb.schemaimportCubicWebSchemaLoaderfromcubicweb.goaimportdbasgoadb# db.Model -> yams ############################################################DBM2Y_TYPESMAP={basestring:String,datastore_types.Text:String,int:Int,float:Float,bool:Boolean,time:Time,date:Date,datetime:Datetime,datastore_types.Blob:Bytes,}defdbm2y_default_factory(prop,**kwargs):"""just wraps the default types map to set basic constraints like `required`, `default`, etc. """yamstype=DBM2Y_TYPESMAP[prop.data_type]if'default'notinkwargs:default=prop.default_value()ifdefaultisnotNone:kwargs['default']=defaultifprop.required:kwargs['required']=Truereturnyamstype(**kwargs)defdbm2y_string_factory(prop):"""like dbm2y_default_factory but also deals with `maxsize` and `vocabulary`"""kwargs={}ifprop.data_typeisbasestring:kwargs['maxsize']=500ifprop.choicesisnotNone:kwargs['vocabulary']=prop.choicesreturndbm2y_default_factory(prop,**kwargs)defdbm2y_date_factory(prop):"""like dbm2y_default_factory but also deals with today / now definition"""kwargs={}ifprop.auto_now_add:ifprop.data_typeisdatetime:kwargs['default']='now'else:kwargs['default']='today'# XXX no equivalent to Django's `auto_now`returndbm2y_default_factory(prop,**kwargs)defdbm2y_relation_factory(etype,prop,multiple=False):"""called if `prop` is a `db.ReferenceProperty`"""ifmultiple:cardinality='**'elifprop.required:cardinality='1*'else:cardinality='?*'# XXX deal with potential kwargs of ReferenceProperty.__init__()try:returnSubjectRelation(prop.data_type.kind(),cardinality=cardinality)exceptAttributeError,ex:# hack, data_type is still _SELF_REFERENCE_MARKERreturnSubjectRelation(etype,cardinality=cardinality)DBM2Y_FACTORY={basestring:dbm2y_string_factory,datastore_types.Text:dbm2y_string_factory,int:dbm2y_default_factory,float:dbm2y_default_factory,bool:dbm2y_default_factory,time:dbm2y_date_factory,date:dbm2y_date_factory,datetime:dbm2y_date_factory,datastore_types.Blob:dbm2y_default_factory,}classGaeSchemaLoader(CubicWebSchemaLoader):"""Google appengine schema loader class"""def__init__(self,*args,**kwargs):self.use_gauthservice=kwargs.pop('use_gauthservice',False)super(GaeSchemaLoader,self).__init__(*args,**kwargs)self.defined={}self.created=[]self.loaded_files=[]self._instantiate_handlers()deffinalize(self,register_base_types=False):returnself._build_schema('google-appengine',register_base_types)defload_dbmodel(self,name,props):clsdict={}ordered_props=sorted(props.items(),key=lambdax:x[1].creation_counter)forpname,propinordered_props:ifisinstance(prop,db.ListProperty):ifnotissubclass(prop.item_type,db.Model):self.error('ignoring list property with %s item type'%prop.item_type)continuerdef=dbm2y_relation_factory(name,prop,multiple=True)else:try:ifisinstance(prop,(db.ReferenceProperty,goadb.ReferencePropertyStub)):rdef=dbm2y_relation_factory(name,prop)else:rdef=DBM2Y_FACTORY[prop.data_type](prop)exceptKeyError,ex:importtracebacktraceback.print_exc()self.error('ignoring property %s (keyerror on %s)'%(pname,ex))continuerdef.creation_rank=prop.creation_counterclsdict[pname]=rdefedef=metadefinition(name,(EntityType,),clsdict)self.add_definition(self,edef())deferror(self,msg):print'ERROR:',msgdefimport_yams_schema(self,ertype,schemamod):erdef=self.pyreader.import_erschema(ertype,schemamod)defimport_yams_cube_schema(self,templpath):forfilepathinself.get_schema_files(templpath):self.handle_file(filepath)@propertydefpyreader(self):returnself._live_handlers['.py']importosfromcubicwebimportCW_SOFTWARE_ROOTifos.environ.get('APYCOT_ROOT'):SCHEMAS_LIB_DIRECTORY=join(os.environ['APYCOT_ROOT'],'local','share','cubicweb','schemas')else:SCHEMAS_LIB_DIRECTORY=join(CW_SOFTWARE_ROOT,'schemas')defload_schema(config,schemaclasses=None,extrahook=None):"""high level method to load all the schema for a lax instance"""# IMPORTANT NOTE: dbmodel schemas must be imported **BEFORE**# the loader is instantiated because this is where the dbmodels# are registered in the yams schemaforcompnameinconfig['included-cubes']:__import__('%s.schema'%compname)loader=GaeSchemaLoader(use_gauthservice=config['use-google-auth'],db=db)loader.lib_directory=SCHEMAS_LIB_DIRECTORYifschemaclassesisnotNone:forclsinschemaclasses:loader.load_dbmodel(cls.__name__,goadb.extract_dbmodel(cls))elifconfig['schema-type']=='dbmodel':importschemaasappschemaforobjinvars(appschema).values():ifisinstance(obj,type)andissubclass(obj,goadb.Model)andobj.__module__==appschema.__name__:loader.load_dbmodel(obj.__name__,goadb.extract_dbmodel(obj))forerschemain('CWGroup','CWEType','CWRType','RQLExpression','is_','is_instance_of','read_permission','add_permission','delete_permission','update_permission'):loader.import_yams_schema(erschema,'bootstrap')loader.handle_file(join(SCHEMAS_LIB_DIRECTORY,'base.py'))cubes=config['included-yams-cubes']forcubeinreversed(config.expand_cubes(cubes)):config.info('loading cube %s',cube)loader.import_yams_cube_schema(config.cube_dir(cube))ifconfig['schema-type']=='yams':loader.import_yams_cube_schema('.')ifextrahookisnotNone:extrahook(loader)ifconfig['use-google-auth']:loader.defined['CWUser'].remove_relation('upassword')loader.defined['CWUser'].permissions['add']=()loader.defined['CWUser'].permissions['delete']=()foretypein('CWGroup','RQLExpression'):read_perm_rel=loader.defined[etype].get_relations('read_permission').next()read_perm_rel.cardinality='**'# XXX not yet ready for CWUser workflowloader.defined['CWUser'].remove_relation('in_state')loader.defined['CWUser'].remove_relation('wf_info_for')# remove RQLConstraint('NOT O name "owners"') on CWUser in_group CWGroup# since "owners" group is not persistent with gaeloader.defined['CWUser'].get_relations('in_group').next().constraints=[]# return the full schema including the cubes' schemaforertypeinloader.defined.values():ifgetattr(ertype,'inlined',False):ertype.inlined=Falsereturnloader.finalize()