[test] do not overwrite user's CW_CUBES_PATH in unittest_migration
Currently when you rely on your CW_CUBES_PATH environment variable to
locate cubes necessary for cubicweb's tests, the migration test crashes
because it overrides the env var.
# 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/>."""rest publishing functionscontains some functions and setup of docutils for cubicweb. Provides thefollowing ReST directives:* `eid`, create link to entity in the repository by their eid* `card`, create link to card entity in the repository by their wikiid (proposing to create it when the refered card doesn't exist yet)* `winclude`, reference to a web documentation file (in wdoc/ directories)* `sourcecode` (if pygments is installed), source code colorization* `rql-table`, create a table from a RQL query"""__docformat__="restructuredtext en"fromitertoolsimportchainfromloggingimportgetLoggerfromos.pathimportjoinfromsiximporttext_typefromsix.moves.urllib.parseimporturlsplitfromdocutilsimportstatemachine,nodes,utils,iofromdocutils.coreimportPublisherfromdocutils.parsers.rstimportParser,states,directives,Directivefromdocutils.parsers.rst.rolesimportregister_canonical_role,set_classesfromlogilab.mtconverterimportESC_UCAR_TABLE,ESC_CAR_TABLE,xml_escapefromcubicwebimportUnknownEidfromcubicweb.ext.html4zopeimportWriterfromcubicweb.web.viewsimportvid_from_rset# XXX better not to import c.w.views here...# We provide our own parser as an attempt to get rid of# state machine reinstanciationimportre# compile states.Body patternsfork,vinstates.Body.patterns.items():ifisinstance(v,str):states.Body.patterns[k]=re.compile(v)# register ReStructured Text mimetype / extensionsimportmimetypesmimetypes.add_type('text/rest','.rest')mimetypes.add_type('text/rest','.rst')LOGGER=getLogger('cubicweb.rest')defeid_reference_role(role,rawtext,text,lineno,inliner,options={},content=[]):try:try:eid_num,rest=text.split(u':',1)exceptValueError:eid_num,rest=text,'#'+texteid_num=int(eid_num)ifeid_num<0:raiseValueErrorexceptValueError:msg=inliner.reporter.error('EID number must be a positive number; "%s" is invalid.'%text,line=lineno)prb=inliner.problematic(rawtext,rawtext,msg)return[prb],[msg]# Base URL mainly used by inliner.pep_reference; so this is correct:context=inliner.document.settings.contexttry:refedentity=context._cw.entity_from_eid(eid_num)exceptUnknownEid:ref='#'rest+=u' '+context._cw._('(UNEXISTANT EID)')else:ref=refedentity.absolute_url()set_classes(options)return[nodes.reference(rawtext,utils.unescape(rest),refuri=ref,**options)],[]defrql_role(role,rawtext,text,lineno,inliner,options={},content=[]):"""``:rql:`<rql-expr>``` or ``:rql:`<rql-expr>:<vid>``` Example: ``:rql:`Any X,Y WHERE X is CWUser, X login Y:table``` Replace the directive with the output of applying the view to the resultset returned by the query. "X eid %(userid)s" can be used in the RQL query for this query will be executed with the argument {'userid': _cw.user.eid}. """_cw=inliner.document.settings.context._cwtext=text.strip()if':'intext:rql,vid=text.rsplit(u':',1)rql=rql.strip()else:rql,vid=text,None_cw.ensure_ro_rql(rql)try:rset=_cw.execute(rql,{'userid':_cw.user.eid})ifrset:ifvidisNone:vid=vid_from_rset(_cw,rset,_cw.vreg.schema)else:vid='noresult'view=_cw.vreg['views'].select(vid,_cw,rset=rset)content=view.render()exceptExceptionasexc:content='an error occurred while interpreting this rql directive: %r'%excset_classes(options)return[nodes.raw('',content,format='html')],[]defbookmark_role(role,rawtext,text,lineno,inliner,options={},content=[]):"""``:bookmark:`<bookmark-eid>``` or ``:bookmark:`<eid>:<vid>``` Example: ``:bookmark:`1234:table``` Replace the directive with the output of applying the view to the resultset returned by the query stored in the bookmark. By default, the view is the one stored in the bookmark, but it can be overridden by the directive as in the example above. "X eid %(userid)s" can be used in the RQL query stored in the Bookmark, for this query will be executed with the argument {'userid': _cw.user.eid}. """_cw=inliner.document.settings.context._cwtext=text.strip()try:if':'intext:eid,vid=text.rsplit(u':',1)eid=int(eid)else:eid,vid=int(text),NoneexceptValueError:msg=inliner.reporter.error('EID number must be a positive number; "%s" is invalid.'%text,line=lineno)prb=inliner.problematic(rawtext,rawtext,msg)return[prb],[msg]try:bookmark=_cw.entity_from_eid(eid)exceptUnknownEid:msg=inliner.reporter.error('Unknown EID %s.'%text,line=lineno)prb=inliner.problematic(rawtext,rawtext,msg)return[prb],[msg]try:params=dict(_cw.url_parse_qsl(urlsplit(bookmark.path).query))rql=params['rql']ifvidisNone:vid=params.get('vid')except(ValueError,KeyError)asexc:msg=inliner.reporter.error('Could not parse bookmark path %s [%s].'%(bookmark.path,exc),line=lineno)prb=inliner.problematic(rawtext,rawtext,msg)return[prb],[msg]try:rset=_cw.execute(rql,{'userid':_cw.user.eid})ifrset:ifvidisNone:vid=vid_from_rset(_cw,rset,_cw.vreg.schema)else:vid='noresult'view=_cw.vreg['views'].select(vid,_cw,rset=rset)content=view.render()exceptExceptionasexc:content='An error occurred while interpreting directive bookmark: %r'%excset_classes(options)return[nodes.raw('',content,format='html')],[]defwinclude_directive(name,arguments,options,content,lineno,content_offset,block_text,state,state_machine):"""Include a reST file as part of the content of this reST file. same as standard include directive but using config.locate_doc_resource to get actual file to include. Most part of this implementation is copied from `include` directive defined in `docutils.parsers.rst.directives.misc` """context=state.document.settings.contextcw=context._cwsource=state_machine.input_lines.source(lineno-state_machine.input_offset-1)#source_dir = os.path.dirname(os.path.abspath(source))fid=arguments[0]forlanginchain((cw.lang,cw.vreg.property_value('ui.language')),cw.vreg.config.available_languages()):rid='%s_%s.rst'%(fid,lang)resourcedir=cw.vreg.config.locate_doc_file(rid)ifresourcedir:breakelse:severe=state_machine.reporter.severe('Problems with "%s" directive path:\nno resource matching %s.'%(name,fid),nodes.literal_block(block_text,block_text),line=lineno)return[severe]path=join(resourcedir,rid)encoding=options.get('encoding',state.document.settings.input_encoding)try:state.document.settings.record_dependencies.add(path)include_file=io.FileInput(source_path=path,encoding=encoding,error_handler=state.document.settings.input_encoding_error_handler,handle_io_errors=None)exceptIOErroraserror:severe=state_machine.reporter.severe('Problems with "%s" directive path:\n%s: %s.'%(name,error.__class__.__name__,error),nodes.literal_block(block_text,block_text),line=lineno)return[severe]try:include_text=include_file.read()exceptUnicodeErroraserror:severe=state_machine.reporter.severe('Problem with "%s" directive:\n%s: %s'%(name,error.__class__.__name__,error),nodes.literal_block(block_text,block_text),line=lineno)return[severe]if'literal'inoptions:literal_block=nodes.literal_block(include_text,include_text,source=path)literal_block.line=1returnliteral_blockelse:include_lines=statemachine.string2lines(include_text,convert_whitespace=1)state_machine.insert_input(include_lines,path)return[]winclude_directive.arguments=(1,0,1)winclude_directive.options={'literal':directives.flag,'encoding':directives.encoding}classRQLTableDirective(Directive):"""rql-table directive Example: .. rql-table:: :vid: mytable :headers: , , progress :colvids: 2=progress Any X,U,X WHERE X is Project, X url U All fields but the RQL string are optionnal. The ``:headers:`` option can contain empty column names. """required_arguments=0optional_arguments=0has_content=Truefinal_argument_whitespace=Trueoption_spec={'vid':directives.unchanged,'headers':directives.unchanged,'colvids':directives.unchanged}defrun(self):errid="rql-table directive"self.assert_has_content()ifself.arguments:raiseself.warning('%s does not accept arguments'%errid)rql=' '.join([l.strip()forlinself.content])_cw=self.state.document.settings.context._cw_cw.ensure_ro_rql(rql)try:rset=_cw.execute(rql)exceptExceptionasexc:raiseself.error("fail to execute RQL query in %s: %r"%(errid,exc))ifnotrset:raiseself.warning("empty result set")vid=self.options.get('vid','table')try:view=_cw.vreg['views'].select(vid,_cw,rset=rset)exceptExceptionasexc:raiseself.error("fail to select '%s' view in %s: %r"%(vid,errid,exc))headers=Noneif'headers'inself.options:headers=[h.strip()forhinself.options['headers'].split(',')]whileheaders.count(''):headers[headers.index('')]=Noneiflen(headers)!=len(rset[0]):raiseself.error("the number of 'headers' does not match the ""number of columns in %s"%errid)cellvids=Noneif'colvids'inself.options:cellvids={}forfinself.options['colvids'].split(','):try:idx,vid=f.strip().split('=')exceptValueError:raiseself.error("malformatted 'colvids' option in %s"%errid)cellvids[int(idx.strip())]=vid.strip()try:content=view.render(headers=headers,cellvids=cellvids)exceptExceptionasexc:raiseself.error("Error rendering %s (%s)"%(errid,exc))return[nodes.raw('',content,format='html')]try:frompygmentsimporthighlightfrompygments.lexersimportget_lexer_by_namefrompygments.formatters.htmlimportHtmlFormatterexceptImportError:pygments_directive=Noneelse:_PYGMENTS_FORMATTER=HtmlFormatter()defpygments_directive(name,arguments,options,content,lineno,content_offset,block_text,state,state_machine):try:lexer=get_lexer_by_name(arguments[0])exceptValueError:# no lexer foundlexer=get_lexer_by_name('text')parsed=highlight(u'\n'.join(content),lexer,_PYGMENTS_FORMATTER)# don't fail if no context set on the sourcecode directivetry:context=state.document.settings.contextcontext._cw.add_css('pygments.css')exceptAttributeError:# used outside cubicweb XXX use hasattr insteadpassreturn[nodes.raw('',parsed,format='html')]pygments_directive.arguments=(1,0,1)pygments_directive.content=1classCubicWebReSTParser(Parser):"""The (customized) reStructuredText parser."""def__init__(self):self.initial_state='Body'self.state_classes=states.state_classesself.inliner=states.Inliner()self.statemachine=states.RSTStateMachine(state_classes=self.state_classes,initial_state=self.initial_state,debug=0)defparse(self,inputstring,document):"""Parse `inputstring` and populate `document`, a document tree."""self.setup_parse(inputstring,document)inputlines=statemachine.string2lines(inputstring,convert_whitespace=1)self.statemachine.run(inputlines,document,inliner=self.inliner)self.finish_parse()# XXX docutils keep a ref on context, can't find a correct way to remove itclassCWReSTPublisher(Publisher):def__init__(self,context,settings,**kwargs):Publisher.__init__(self,**kwargs)self.set_components('standalone','restructuredtext','pseudoxml')self.process_programmatic_settings(None,settings,None)self.settings.context=contextdefrest_publish(context,data):"""publish a string formatted as ReStructured Text to HTML :type context: a cubicweb application object :type data: str :param data: some ReST text :rtype: unicode :return: the data formatted as HTML or the original data if an error occurred """req=context._cwifisinstance(data,text_type):encoding='unicode'# remove unprintable characters unauthorized in xmldata=data.translate(ESC_UCAR_TABLE)else:encoding=req.encoding# remove unprintable characters unauthorized in xmldata=data.translate(ESC_CAR_TABLE)settings={'input_encoding':encoding,'output_encoding':'unicode','warning_stream':False,'traceback':True,# don't sys.exit'stylesheet':None,# don't try to embed stylesheet (may cause# obscure bug due to docutils computing# relative path according to the directory# used *at import time*# dunno what's the max, severe is 4, and we never want a crash# (though try/except may be a better option...). May be the# above traceback option will avoid this?'halt_level':10,}ifcontext:ifhasattr(req,'url'):base_url=req.url()elifhasattr(context,'absolute_url'):base_url=context.absolute_url()else:base_url=req.base_url()else:base_url=Nonetry:pub=CWReSTPublisher(context,settings,parser=CubicWebReSTParser(),writer=Writer(base_url=base_url),source_class=io.StringInput,destination_class=io.StringOutput)pub.set_source(data)pub.set_destination()res=pub.publish(enable_exit_status=None)# necessary for proper garbage collection, else a ref is kept somewhere in docutils...delpub.settings.contextreturnresexceptBaseException:LOGGER.exception('error while publishing ReST text')ifnotisinstance(data,text_type):data=text_type(data,encoding,'replace')returnxml_escape(req._('error while publishing ReST text')+'\n\n'+data)_INITIALIZED=Falsedefcw_rest_init():global_INITIALIZEDif_INITIALIZED:return_INITIALIZED=Trueregister_canonical_role('eid',eid_reference_role)register_canonical_role('rql',rql_role)register_canonical_role('bookmark',bookmark_role)directives.register_directive('winclude',winclude_directive)ifpygments_directiveisnotNone:directives.register_directive('sourcecode',pygments_directive)directives.register_directive('rql-table',RQLTableDirective)