[schema] fix spurious warning when rqlexpr/constraint mainvars specify a non predefined variable. Closes #3098165
# copyright 2003-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 utilities for the CubicWeb server."""__docformat__="restructuredtext en"importsysimportloggingfromthreadingimportTimer,Threadfromgetpassimportgetpassfrompasslib.utilsimporthandlersasuh,to_hash_strfrompasslib.contextimportCryptContextfromcubicweb.md5cryptimportcryptasmd5cryptclassCustomMD5Crypt(uh.HasSalt,uh.GenericHandler):name='cubicwebmd5crypt'setting_kwds=('salt',)min_salt_size=0max_salt_size=8salt_chars=uh.H64_CHARS@classmethoddeffrom_string(cls,hash):salt,chk=uh.parse_mc2(hash,u'')ifchkisNone:raiseValueError('missing checksum')returncls(salt=salt,checksum=chk)defto_string(self):returnto_hash_str(u'%s$%s'%(self.salt,self.checksumoru''))# passlib 1.5 wants calc_checksum, 1.6 wants _calc_checksumdefcalc_checksum(self,secret):returnmd5crypt(secret,self.salt.encode('ascii')).decode('utf-8')_calc_checksum=calc_checksum_CRYPTO_CTX=CryptContext(['sha512_crypt',CustomMD5Crypt,'des_crypt','ldap_salted_sha1'],deprecated=['cubicwebmd5crypt','des_crypt'])verify_and_update=_CRYPTO_CTX.verify_and_updatedefcrypt_password(passwd,salt=None):"""return the encrypted password using the given salt or a generated one """ifsaltisNone:return_CRYPTO_CTX.encrypt(passwd)# empty hash, accept any password for backwards compatifsalt=='':returnsalttry:if_CRYPTO_CTX.verify(passwd,salt):returnsaltexceptValueError:# e.g. couldn't identify hashpass# wrong passwordreturn''defcartesian_product(seqin):"""returns a generator which returns the cartesian product of `seqin` for more details, see : http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/302478 """defrloop(seqin,comb):"""recursive looping function"""ifseqin:# any more sequences to process?foriteminseqin[0]:newcomb=comb+[item]# add next item to current combination# call rloop w/ remaining seqs, newcombforiteminrloop(seqin[1:],newcomb):yielditem# seqs and newcombelse:# processing last sequenceyieldcomb# comb finished, add to listreturnrloop(seqin,[])defeschema_eid(session,eschema):"""get eid of the CWEType entity for the given yams type. You should use this because when schema has been loaded from the file-system, not from the database, (e.g. during tests), eschema.eid is not set. """ifeschema.eidisNone:eschema.eid=session.execute('Any X WHERE X is CWEType, X name %(name)s',{'name':str(eschema)})[0][0]returneschema.eidDEFAULT_MSG='we need a manager connection on the repository \(the server doesn\'t have to run, even should better not)'defmanager_userpasswd(user=None,msg=DEFAULT_MSG,confirm=False,passwdmsg='password'):ifnotuser:ifmsg:printmsgwhilenotuser:user=raw_input('login: ')user=unicode(user,sys.stdin.encoding)passwd=getpass('%s: '%passwdmsg)ifconfirm:whileTrue:passwd2=getpass('confirm password: ')ifpasswd==passwd2:breakprint'password doesn\'t match'passwd=getpass('password: ')# XXX decode password using stdin encoding then encode it using appl'encodingreturnuser,passwd_MARKER=object()deffunc_name(func):name=getattr(func,'__name__',_MARKER)ifnameis_MARKER:name=getattr(func,'func_name',_MARKER)ifnameis_MARKER:name=repr(func)returnnameclassLoopTask(object):"""threaded task restarting itself once executed"""def__init__(self,tasks_manager,interval,func,args):ifinterval<0:raiseValueError('Loop task interval must be >= 0 ''(current value: %f for %s)'% \(interval,func_name(func)))self._tasks_manager=tasks_managerself.interval=intervaldefauto_restart_func(self=self,func=func,args=args):restart=Truetry:func(*args)exceptException:logger=logging.getLogger('cubicweb.repository')logger.exception('Unhandled exception in LoopTask %s',self.name)raiseexceptBaseException:restart=Falsefinally:ifrestartandtasks_manager.running:self.start()self.func=auto_restart_funcself.name=func_name(func)def__str__(self):return'%s (%s seconds)'%(self.name,self.interval)defstart(self):self._t=Timer(self.interval,self.func)self._t.setName('%s-%s[%d]'%(self._t.getName(),self.name,self.interval))self._t.start()defcancel(self):self._t.cancel()defjoin(self):ifself._t.isAlive():self._t.join()classRepoThread(Thread):"""subclass of thread so it auto remove itself from a given list once executed """def__init__(self,target,running_threads):defauto_remove_func(self=self,func=target):try:func()exceptException:logger=logging.getLogger('cubicweb.repository')logger.exception('Unhandled exception in RepoThread %s',self._name)raisefinally:self.running_threads.remove(self)Thread.__init__(self,target=auto_remove_func)self.running_threads=running_threadsself._name=func_name(target)defstart(self):self.running_threads.append(self)self.daemon=TrueThread.start(self)defgetName(self):return'%s(%s)'%(self._name,Thread.getName(self))classTasksManager(object):"""Object dedicated manage background task"""def__init__(self):self.running=Falseself._tasks=[]self._looping_tasks=[]defadd_looping_task(self,interval,func,*args):"""register a function to be called every `interval` seconds. If interval is negative, no looping task is registered. """ifinterval<0:self.debug('looping task %s ignored due to interval %f < 0',func_name(func),interval)returntask=LoopTask(self,interval,func,args)ifself.running:self._start_task(task)else:self._tasks.append(task)def_start_task(self,task):self._looping_tasks.append(task)self.info('starting task %s with interval %.2fs',task.name,task.interval)task.start()defstart(self):"""Start running looping task"""assertself.running==False# bw compat purpose maintlywhileself._tasks:task=self._tasks.pop()self._start_task(task)self.running=Truedefstop(self):"""Stop all running task. returns when all task have been cancel and none are running anymore"""ifself.running:whileself._looping_tasks:looptask=self._looping_tasks.pop()self.info('canceling task %s...',looptask.name)looptask.cancel()looptask.join()self.info('task %s finished',looptask.name)fromloggingimportgetLoggerfromcubicwebimportset_log_methodsset_log_methods(TasksManager,getLogger('cubicweb.repository'))