[py3k] import HTTP client constants and exceptions using six.moves
# copyright 2003-2011 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/>."""Associate url's path to view identifier / rql queries.CubicWeb finds all registered URLPathEvaluators, orders them accordingto their ``priority`` attribute and calls their ``evaluate_path()``method. The first that returns something and doesn't raise a``PathDontMatch`` exception wins.Here is the default evaluator chain:1. :class:`cubicweb.web.views.urlpublishing.RawPathEvaluator` handles unique url segments that match exactly one of the registered controller's *__regid__*. Urls such as */view?*, */edit?*, */json?* fall in that category;2. :class:`cubicweb.web.views.urlpublishing.EidPathEvaluator` handles unique url segments that are eids (e.g. */1234*);3. :class:`cubicweb.web.views.urlpublishing.URLRewriteEvaluator` selects all urlrewriter components, sorts them according to their priority, call their ``rewrite()`` method, the first one that doesn't raise a ``KeyError`` wins. This is where the :mod:`cubicweb.web.views.urlrewrite` and :class:`cubicweb.web.views.urlrewrite.SimpleReqRewriter` comes into play;4. :class:`cubicweb.web.views.urlpublishing.RestPathEvaluator` handles urls based on entity types and attributes : <etype>((/<attribute name>])?/<attribute value>)? This is why ``cwuser/carlos`` works;5. :class:`cubicweb.web.views.urlpublishing.ActionPathEvaluator` handles any of the previous paths with an additional trailing "/<action>" segment, <action> being one of the registered actions' __regid__... note:: Actionpath executes a query whose results is lost because of redirecting instead of direct traversal."""__docformat__="restructuredtext en"fromrqlimportTypeResolverExceptionfromcubicwebimportRegistryExceptionfromcubicweb.webimportNotFound,Redirect,component,viewsclassPathDontMatch(Exception):"""exception used by url evaluators to notify they can't evaluate a path """classURLPublisherComponent(component.Component):"""Associate url path to view identifier / rql queries, by applying a chain of urlpathevaluator components. An evaluator is a URLPathEvaluator subclass with an .evaluate_path method taking the request object and the path to publish as argument. It will either return a publishing method identifier and an rql query on success or raise a `PathDontMatch` exception on failure. URL evaluators are called according to their `priority` attribute, with 0 as the greatest priority and greater values as lower priority. The first evaluator returning a result or raising something else than `PathDontMatch` will stop the handlers chain. """__regid__='urlpublisher'vreg=None# XXX necessary until property for deprecation warning is on appobjectdef__init__(self,vreg,default_method='view'):super(URLPublisherComponent,self).__init__()self.vreg=vregself.default_method=default_methodevaluators=[]forevaluatorclsinvreg['components']['urlpathevaluator']:# instantiation neededevaluator=evaluatorcls(self)evaluators.append(evaluator)self.evaluators=sorted(evaluators,key=lambdax:x.priority)defprocess(self,req,path):"""Given a URL (essentially characterized by a path on the server, but additional information may be found in the request object), return a publishing method identifier (e.g. controller) and an optional result set. :type req: `cubicweb.web.request.CubicWebRequestBase` :param req: the request object :type path: str :param path: the path of the resource to publish. If empty, None or "/" "view" is used as the default path. :rtype: tuple(str, `cubicweb.rset.ResultSet` or None) :return: the publishing method identifier and an optional result set :raise NotFound: if no handler is able to decode the given path """parts=[partforpartinpath.split('/')ifpart!='']or(self.default_method,)ifreq.form.get('rql'):ifparts[0]inself.vreg['controllers']:returnparts[0],Nonereturn'view',Noneforevaluatorinself.evaluators:try:pmid,rset=evaluator.evaluate_path(req,parts[:])breakexceptPathDontMatch:continueelse:raiseNotFound(path)ifpmidisNone:pmid=self.default_methodreturnpmid,rsetclassURLPathEvaluator(component.Component):__abstract__=True__regid__='urlpathevaluator'vreg=None# XXX necessary until property for deprecation warning is on appobjectdef__init__(self,urlpublisher):self.urlpublisher=urlpublisherself.vreg=urlpublisher.vregclassRawPathEvaluator(URLPathEvaluator):"""handle path of the form:: <publishing_method>?parameters... """priority=0defevaluate_path(self,req,parts):iflen(parts)==1andparts[0]inself.vreg['controllers']:returnparts[0],NoneraisePathDontMatch()classEidPathEvaluator(URLPathEvaluator):"""handle path with the form:: <eid> """priority=1defevaluate_path(self,req,parts):iflen(parts)!=1:raisePathDontMatch()try:rset=req.execute('Any X WHERE X eid %(x)s',{'x':int(parts[0])})exceptValueError:raisePathDontMatch()ifrset.rowcount==0:raiseNotFound()returnNone,rsetclassRestPathEvaluator(URLPathEvaluator):"""handle path with the form:: <etype>[[/<attribute name>]/<attribute value>]* """priority=3defevaluate_path(self,req,parts):ifnot(0<len(parts)<4):raisePathDontMatch()try:etype=self.vreg.case_insensitive_etypes[parts.pop(0).lower()]exceptKeyError:raisePathDontMatch()cls=self.vreg['etypes'].etype_class(etype)ifparts:iflen(parts)==2:attrname=parts.pop(0).lower()try:cls.e_schema.subjrels[attrname]exceptKeyError:raisePathDontMatch()else:attrname=cls.cw_rest_attr_info()[0]value=req.url_unquote(parts.pop(0))returnself.handle_etype_attr(req,cls,attrname,value)returnself.handle_etype(req,cls)defset_vid_for_rset(self,req,cls,rset):# cls is there to ease overridingifrset.rowcount==0:raiseNotFound()if'vid'notinreq.form:# check_table=False tells vid_from_rset not to try to use a table view if fetch_rql# include some non final relationreq.form['vid']=views.vid_from_rset(req,rset,req.vreg.schema,check_table=False)defhandle_etype(self,req,cls):rset=req.execute(cls.fetch_rql(req.user))self.set_vid_for_rset(req,cls,rset)returnNone,rsetdefhandle_etype_attr(self,req,cls,attrname,value):st=cls.fetch_rqlst(req.user,ordermethod=None)st.add_constant_restriction(st.get_variable('X'),attrname,'x','Substitute')ifattrname=='eid':try:rset=req.execute(st.as_string(),{'x':int(value)})except(ValueError,TypeResolverException):# conflicting eid/typeraisePathDontMatch()else:rset=req.execute(st.as_string(),{'x':value})self.set_vid_for_rset(req,cls,rset)returnNone,rsetclassURLRewriteEvaluator(URLPathEvaluator):"""tries to find a rewrite rule to apply URL rewrite rule definitions are stored in URLRewriter objects """priority=2defevaluate_path(self,req,parts):# uri <=> req._twreq.path or req._twreq.uriuri=req.url_unquote('/'+'/'.join(parts))evaluators=sorted(self.vreg['urlrewriting'].all_objects(),key=lambdax:x.priority,reverse=True)forrewriterclsinevaluators:rewriter=rewritercls(req)try:# XXX we might want to chain url rewritesreturnrewriter.rewrite(req,uri)exceptKeyError:continueraisePathDontMatch()classActionPathEvaluator(URLPathEvaluator):"""handle path with the form:: <any evaluator path>/<action> """priority=4defevaluate_path(self,req,parts):iflen(parts)<2:raisePathDontMatch()# remove last part and see if this is something like an actions# if so, call# XXX bad smell: refactor to simpler codetry:actionsreg=self.vreg['actions']requested=parts.pop(-1)actions=actionsreg[requested]exceptRegistryException:raisePathDontMatch()forevaluatorinself.urlpublisher.evaluators:ifevaluatorisselforevaluator.priority==0:continuetry:pmid,rset=evaluator.evaluate_path(req,parts[:])exceptPathDontMatch:continueelse:try:action=actionsreg._select_best(actions,req,rset=rset)ifactionisnotNone:raiseRedirect(action.url())exceptRegistryException:pass# continue searchingraisePathDontMatch()