[book] remove dbapi documentation
Move some still-relevant doc related to the RQL connection API to the
'sessions' section. It might make sense to move this back outside of
the "Repository development" chapter at some point since this is
relevant in other contexts.
# copyright 2010-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr## This file is part of CubicWeb.## CubicWeb is free software: you can redistribute it and/or modify it under the# terms of the GNU Lesser General Public License as published by the Free# Software Foundation, either version 2.1 of the License, or (at your option)# any later version.## CubicWeb is distributed in the hope that it will be useful, but WITHOUT# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more# details.## You should have received a copy of the GNU Lesser General Public License along# with CubicWeb. If not, see <http://www.gnu.org/licenses/>."""some basic entity adapter implementations, for interfaces used in theframework itself."""__docformat__="restructuredtext en"_=unicodefromitertoolsimportchainfromwarningsimportwarnfromlogilab.mtconverterimportTransformErrorfromlogilab.common.decoratorsimportcachedfromcubicwebimportValidationError,viewfromcubicweb.predicatesimportis_instance,relation_possible,match_exceptionclassIEmailableAdapter(view.EntityAdapter):__regid__='IEmailable'__select__=relation_possible('primary_email')|relation_possible('use_email')defget_email(self):ifgetattr(self.entity,'primary_email',None):returnself.entity.primary_email[0].addressifgetattr(self.entity,'use_email',None):returnself.entity.use_email[0].addressreturnNonedefallowed_massmail_keys(self):"""returns a set of allowed email substitution keys The default is to return the entity's attribute list but you might override this method to allow extra keys. For instance, a Person class might want to return a `companyname` key. """returnset(rschema.typeforrschema,attrtypeinself.entity.e_schema.attribute_definitions()ifattrtype.typenotin('Password','Bytes'))defas_email_context(self):"""returns the dictionary as used by the sendmail controller to build email bodies. NOTE: the dictionary keys should match the list returned by the `allowed_massmail_keys` method. """returndict((attr,getattr(self.entity,attr))forattrinself.allowed_massmail_keys())classINotifiableAdapter(view.EntityAdapter):__regid__='INotifiable'__select__=is_instance('Any')defnotification_references(self,view):"""used to control References field of email send on notification for this entity. `view` is the notification view. Should return a list of eids which can be used to generate message identifiers of previously sent email(s) """itree=self.entity.cw_adapt_to('ITree')ifitreeisnotNone:returnitree.path()[:-1]ifview.msgid_timestamp:return(self.entity.eid,)return()classIFTIndexableAdapter(view.EntityAdapter):"""standard adapter to handle fulltext indexing .. automethod:: cubicweb.entities.adapters.IFTIndexableAdapter.fti_containers .. automethod:: cubicweb.entities.adapters.IFTIndexableAdapter.get_words """__regid__='IFTIndexable'__select__=is_instance('Any')deffti_containers(self,_done=None):"""return the list of entities to index when handling ``self.entity`` The actual list of entities depends on ``fulltext_container`` usage in the datamodel definition """if_doneisNone:_done=set()entity=self.entity_done.add(entity.eid)containers=tuple(entity.e_schema.fulltext_containers())ifcontainers:forrschema,roleincontainers:ifrole=='object':targets=getattr(entity,rschema.type)else:targets=getattr(entity,'reverse_%s'%rschema)fortargetintargets:iftarget.eidin_done:continueforcontainerintarget.cw_adapt_to('IFTIndexable').fti_containers(_done):yieldcontainerelse:yieldentity# weight in ABCDentity_weight=1.0attr_weight={}defget_words(self):"""used by the full text indexer to get words to index this method should only be used on the repository side since it depends on the logilab.database package :rtype: list :return: the list of indexable word of this entity """fromlogilab.database.ftiimporttokenize# take care to cases where we're modyfying the schemaentity=self.entitypending=self._cw.transaction_data.setdefault('pendingrdefs',set())words={}forrschemainentity.e_schema.indexable_attributes():if(entity.e_schema,rschema)inpending:continueweight=self.attr_weight.get(rschema,'C')try:value=entity.printable_value(rschema,format='text/plain')exceptTransformError:continueexceptException:self.exception("can't add value of %s to text index for entity %s",rschema,entity.eid)continueifvalue:words.setdefault(weight,[]).extend(tokenize(value))forrschema,roleinentity.e_schema.fulltext_relations():ifrole=='subject':forentity_ingetattr(entity,rschema.type):merge_weight_dict(words,entity_.cw_adapt_to('IFTIndexable').get_words())else:# if role == 'object':forentity_ingetattr(entity,'reverse_%s'%rschema.type):merge_weight_dict(words,entity_.cw_adapt_to('IFTIndexable').get_words())returnwordsdefmerge_weight_dict(maindict,newdict):forweight,wordsinnewdict.iteritems():maindict.setdefault(weight,[]).extend(words)classIDownloadableAdapter(view.EntityAdapter):"""interface for downloadable entities"""__regid__='IDownloadable'__abstract__=Truedefdownload_url(self,**kwargs):# XXX not really part of this interface"""return a URL to download entity's content"""raiseNotImplementedErrordefdownload_content_type(self):"""return MIME type of the downloadable content"""raiseNotImplementedErrordefdownload_encoding(self):"""return encoding of the downloadable content"""raiseNotImplementedErrordefdownload_file_name(self):"""return file name of the downloadable content"""raiseNotImplementedErrordefdownload_data(self):"""return actual data of the downloadable content"""raiseNotImplementedError# XXX should propose to use two different relations for children/parentclassITreeAdapter(view.EntityAdapter):"""This adapter provides a tree interface. It has to be overriden to be configured using the tree_relation, child_role and parent_role class attributes to benefit from this default implementation. This class provides the following methods: .. automethod: iterparents .. automethod: iterchildren .. automethod: prefixiter .. automethod: is_leaf .. automethod: is_root .. automethod: root .. automethod: parent .. automethod: children .. automethod: different_type_children .. automethod: same_type_children .. automethod: children_rql .. automethod: path """__regid__='ITree'__abstract__=Truechild_role='subject'parent_role='object'defchildren_rql(self):"""Returns RQL to get the children of the entity."""returnself.entity.cw_related_rql(self.tree_relation,self.parent_role)defdifferent_type_children(self,entities=True):"""Return children entities of different type as this entity. According to the `entities` parameter, return entity objects or the equivalent result set. """res=self.entity.related(self.tree_relation,self.parent_role,entities=entities)eschema=self.entity.e_schemaifentities:return[eforeinresife.e_schema!=eschema]returnres.filtered_rset(lambdax:x.e_schema!=eschema,self.entity.cw_col)defsame_type_children(self,entities=True):"""Return children entities of the same type as this entity. According to the `entities` parameter, return entity objects or the equivalent result set. """res=self.entity.related(self.tree_relation,self.parent_role,entities=entities)eschema=self.entity.e_schemaifentities:return[eforeinresife.e_schema==eschema]returnres.filtered_rset(lambdax:x.e_schemaiseschema,self.entity.cw_col)defis_leaf(self):"""Returns True if the entity does not have any children."""returnlen(self.children())==0defis_root(self):"""Returns true if the entity is root of the tree (e.g. has no parent). """returnself.parent()isNonedefroot(self):"""Return the root entity of the tree."""returnself._cw.entity_from_eid(self.path()[0])defparent(self):"""Returns the parent entity if any, else None (e.g. if we are on the root). """try:returnself.entity.related(self.tree_relation,self.child_role,entities=True)[0]except(KeyError,IndexError):returnNonedefchildren(self,entities=True,sametype=False):"""Return children entities. According to the `entities` parameter, return entity objects or the equivalent result set. """ifsametype:returnself.same_type_children(entities)else:returnself.entity.related(self.tree_relation,self.parent_role,entities=entities)defiterparents(self,strict=True):"""Return an iterator on the parents of the entity."""def_uptoroot(self):curr=selfwhileTrue:curr=curr.parent()ifcurrisNone:breakyieldcurrcurr=curr.cw_adapt_to('ITree')ifnotstrict:returnchain([self.entity],_uptoroot(self))return_uptoroot(self)defiterchildren(self,_done=None):"""Return an iterator over the item's children."""if_doneisNone:_done=set()forchildinself.children():ifchild.eidin_done:self.error('loop in %s tree: %s',child.cw_etype.lower(),child)continueyieldchild_done.add(child.eid)defprefixiter(self,_done=None):"""Return an iterator over the item's descendants in a prefixed order."""if_doneisNone:_done=set()ifself.entity.eidin_done:return_done.add(self.entity.eid)yieldself.entityforchildinself.same_type_children():forentityinchild.cw_adapt_to('ITree').prefixiter(_done):yieldentity@cacheddefpath(self):"""Returns the list of eids from the root object to this object."""path=[]adapter=selfentity=adapter.entitywhileentityisnotNone:ifentity.eidinpath:self.error('loop in %s tree: %s',entity.cw_etype.lower(),entity)breakpath.append(entity.eid)try:# check we are not jumping to another treeif(adapter.tree_relation!=self.tree_relationoradapter.child_role!=self.child_role):breakentity=adapter.parent()adapter=entity.cw_adapt_to('ITree')exceptAttributeError:breakpath.reverse()returnpath# error handling adapters ######################################################fromcubicwebimportUniqueTogetherErrorclassIUserFriendlyError(view.EntityAdapter):__regid__='IUserFriendlyError'__abstract__=Truedef__init__(self,*args,**kwargs):self.exc=kwargs.pop('exc')super(IUserFriendlyError,self).__init__(*args,**kwargs)classIUserFriendlyUniqueTogether(IUserFriendlyError):__select__=match_exception(UniqueTogetherError)defraise_user_exception(self):rtypes=self.exc.rtypeserrors={}msgargs={}i18nvalues=[]forrtypeinrtypes:errors[rtype]=_('%(KEY-rtype)s is part of violated unicity constraint')msgargs[rtype+'-rtype']=rtypei18nvalues.append(rtype+'-rtype')errors['']=_('some relations violate a unicity constraint')raiseValidationError(self.entity.eid,errors,msgargs=msgargs,i18nvalues=i18nvalues)