fix extid handling: ensure encoded string is given, and store them as base64 (see note in native.py).
Bump version to force migration on dev instances.
"""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), all rights reserved.:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr"""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 application"""# 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()