#!/usr/bin/env python# -*- coding: utf-8 -*-## This file is part of the `pypath` python module## Copyright 2014-2023# EMBL, EMBL-EBI, Uniklinik RWTH Aachen, Heidelberg University## Authors: see the file `README.rst`# Contact: Dénes Türei (turei.denes@gmail.com)## Distributed under the GPLv3 License.# See accompanying file LICENSE.txt or copy at# https://www.gnu.org/licenses/gpl-3.0.html## Website: https://pypath.omnipathdb.org/#fromfuture.utilsimportiteritemsimportsysimportosimportreimportcopyimportcollectionsimportitertoolsimporthashlibimportwarningsimportcontextlibfrompypath.shareimportsessionassession_mod_logger=session_mod.Logger(name='server')_log=_logger._logtry:importtwisted.web.resourceimporttwisted.web.serverimporttwisted.internet.reactorTwistedWebResource=twisted.web.resource.ResourceTwistedWebSite=twisted.web.server.SiteTWISTED_NOT_DONE_YET=twisted.web.server.NOT_DONE_YETtwisted_listen_tcp=twisted.internet.reactor.listenTCPtwisted_run=twisted.internet.reactor.runexcept:_log('No module `twisted` available. Necessary to run HTTP server.',-1)
[docs]def__init__(self):ifnothasattr(self,'_log_name'):session_mod.Logger.__init__(name='server')self._log('Initializing BaseServer.')self.htmls=['info','error_page.html']self.welcome_message=('Hello, this is the REST service of pypath %s. Welcome!\n''For the descriptions of pathway resources go to `/info`.\n''Available query types: interactions, enz_sub, complexes, \n''annotations, intercell')%__version__self.isLeaf=Trueself._set_www_root()self._read_license_secret()self._res_ctrl=resources_mod.get_controller()TwistedWebResource.__init__(self)self._log('Twisted resource initialized.')
defrender_GET(self,request):response=[]request.postpath=[i.decode('utf-8')foriinrequest.postpathifi]self._log('Processing request: `%s` from `%s`; headers: [%s].'%(request.uri.decode('utf-8'),str(request.getClientAddress()),common.dict_str(request.getAllHeaders()),))ifnotrequest.postpath:request.postpath=['index.html']request.postpath[0]=self._query_type(request.postpath[0])self._set_headers(request)if(request.postpathand(hasattr(self,request.postpath[0])orrequest.postpath[0]=='error_page.html')andrequest.postpath[0][0]!='_'):ifrequest.postpath[0]=='error_page.html':toCall=self._error_pageelse:self._process_postpath(request)toCall=getattr(self,request.postpath[0])ifhasattr(toCall,'__call__'):self._log('Query type: `%s`; Arguments: [%s].'%(request.postpath[0],common.dict_str(request.args),))try:response=toCall(request)response=(response.encode('utf-8')ifhasattr(response,'encode')elseresponse)response=[response]except:self._log('Error while rendering `%s`:'%request.uri.decode('utf-8'))self._log_traceback()raiseelse:local_path=self._local_path(request)iflocal_path:withopen(local_path,'rb')asfp:response=[fp.read()]response=self._add_html_header(local_path,response)ifnotresponse:response=[("Not found: %s%s"%('/'.join(request.postpath),''iflen(request.args)==0else'?%s'%'&'.join(['%s=%s'%(k.decode('utf-8'),v[0].decode('utf-8'))fork,viniteritems(request.args)ifv]))).encode('utf-8')]request.setHeader('Content-Length',str(len(response[0])))request.write(response[0])self._log('Finished serving request: `%s`.'%request.uri.decode('utf-8'))request.finish()returnTWISTED_NOT_DONE_YETdefrender_POST(self,request):if(request.getHeader(b'content-type')andrequest.getHeader(b'content-type').startswith(b'application/json')):post_content=request.content.getvalue()ifpost_contentandpost_content.strip():args_raw=json.loads(post_content)request.args=dict((k.encode('utf-8'),[v.encode('utf-8')]iftype(v)isnotlistelse[','.join(v).encode('utf-8')])fork,viniteritems(args_raw))returnself.render_GET(request)def_set_www_root(self):self.wwwbuiltin=os.path.join(session_mod.session().module_root,'data','www',)self.wwwroot=settings.get('www_root')ifnotos.path.exists(self.wwwroot):self.wwwroot=self.wwwbuiltindef_local_path(self,request):ifrequest.postpathandrequest.postpath[-1][0]in('_','.'):returnforwwwrootin(self.wwwroot,self.wwwbuiltin):path=os.path.join(wwwroot,*request.postpath)ifos.path.isfile(path):returnpathdef_set_headers(self,request):fork,viniteritems(request.args):request.args[k]=[b','.join(v)]request.setHeader('Cache-Control','Public')request.setHeader('Access-Control-Allow-Origin','*')if''inrequest.postpath:request.postpath.remove('')ifnotrequest.postpath:request.postpath=['index.html']ifrequest.postpathandrequest.postpath[0]=='resources':request.args[b'format']=[b'json']local_path=self._local_path(request)iflocal_path:format_=mimetypes.guess_type(local_path)[0]format_=(tuple(format_.split('/'))ifformat_else('text','plain'))elif(notrequest.postpathorrequest.postpath[0]inself.htmlsorrequest.postpath[0]=='error_page.html'):format_=('text','html')elif(b'format'inrequest.argsandrequest.args[b'format'][0]==b'json'):format_=('application','json')elifrequest.postpath[0]=='favicon.ico':format_=('image','vnd.microsoft.icon')else:request.args[b'format']=[b'text']format_=('text','plain')request.setHeader('Content-Type','%s/%s%s'%(format_+('; charset=utf-8'ifformat_[0]=='text'else'',)))request.args[b'header']=([b'1']ifb'header'notinrequest.argselserequest.args[b'header'])self._set_fields(request)self._set_license(request)def_set_fields(self,req):synonyms=(self.field_synonymsifhasattr(self,'field_synonyms')else{})ifb'fields'inreq.args:used=set()fields_checked=[]forfieldinreq.args[b'fields'][0].decode('utf-8').split(','):field=synonyms[field]iffieldinsynonymselsefieldiffieldnotinused:fields_checked.append(field)used.add(field)req.args[b'fields']=[','.join(fields_checked).encode('utf-8')]else:req.args[b'fields']=[]def_set_license(self,req):query_type=req.postpath[0]ifreq.postpathelseNonequery_type=self._query_type(query_type)if(nothasattr(self,'args_reference')ornotquery_typeorquery_typenotinself.args_referenceor'license'notinself.args_reference[query_type]):returnauth=Falseifb'password'inreq.args:req_secret=hashlib.md5(req.args[b'password'][0]).hexdigest()auth=(self._license_secretisnotNoneandself._license_secret==req_secret)# if someone sent a good password# why not to ignore the licensesifauth:req.args[b'license']=[b'ignore']# if the license level is not set# or set to `ignore` but no successfull authentication# we fall back to the default license levelif(b'license'notinreq.argsor(notauthandreq.args[b'license'][0]==b'ignore')):req.args[b'license']=self._default_licensedef_process_postpath(self,req):iflen(req.postpath)>1:ids_left=[req.postpath[1].encode('utf-8')]ids_right=([req.postpath[2].encode('utf-8')]if(len(req.postpath)>2andreq.postpath[2].lower()notin{'and','or'})elseNone)left_right=([b'OR']ifreq.postpath[-1].lower()notin{'and','or'}else[req.postpath[-1].encode('utf-8')])ifids_right:ifreq.postpath[0]=='enzsub':req.args[b'enzymes']=ids_leftreq.args[b'substrates']=ids_rightelse:req.args[b'sources']=ids_leftreq.args[b'targets']=ids_rightelse:req.args[b'partners']=ids_leftifreq.postpath[0]=='enzsub':req.args[b'enzyme_substrate']=left_rightelse:req.args[b'source_target']=left_rightdef_query_type(self,query_type):return(self.query_type_synonyms[query_type]if(hasattr(self,'query_type_synonyms')andquery_typeinself.query_type_synonyms)elsequery_type)def_add_html_header(self,local_path,response):if(local_path.endswith('html')orlocal_path.endswith('htm'))andnotresponse[0].startswith(b'<!DOCTYPE html>'):head_foot=[(b'<!DOCTYPE html>\n<html lang="en">\n'b'<head><title>%s</title></head>\n<body>\n'),b'</body>\n</html>',]forwwwrootin(self.wwwroot,self.wwwbuiltin):fori,partinenumerate(('header','footer')):path=os.path.join(wwwroot,'_%s.html'%part)ifos.path.exists(path):withopen(path,'rb')asfp:head_foot[i]=fp.read()ifb'%s'inhead_foot[0]:title=self.recomment.search(response[0])title=title.groups()[0]iftitleelseb'pypath server'head_foot[0]=head_foot[0]%title.strip()response[0]=head_foot[0]+response[0]+head_foot[1]returnresponsedefabout(self,req):returnself.welcome_messagedefinfo(self,req):if(b'format'inreq.argsandreq.args[b'format'][0]==b'json'andhasattr(self,'resources')):returnself.resources(req)rc=resources.get_controller()rc.update()returngenerate_about_page.generate_about_html(rc.data)def_root(self,req):return_html.main_page()def_parse_arg(self,arg):ifisinstance(arg,list)andarg:arg=arg[0]ifhasattr(arg,'decode'):arg=arg.decode('utf-8')ifhasattr(arg,'lower'):arg=arg.lower()ifhasattr(arg,'isdigit')andarg.isdigit():arg=int(arg)ifargin_const.BOOLEAN_FALSE:arg=Falseifargin_const.BOOLEAN_TRUE:arg=Truereturnbool(arg)def_read_license_secret(self):self._license_secret=Nonepath=settings.get('license_secret')ifos.path.exists(path):self._log('Reading license unlocking secret from `%s`.'%path)withopen(path,'r')asfp:self._license_secret=fp.read().strip()self._default_license=[settings.get('server_default_license').encode('ascii')]def_error_page(self,req):req.setResponseCode(500)return_html.http_500()
[docs]classTableServer(BaseServer):query_types={'annotations','intercell','interactions','enz_sub','enzsub','ptms','complexes','about','info','queries','annotations_summary','intercell_summary',}data_query_types={'annotations','intercell','interactions','enzsub','complexes',}list_fields={'sources','references','isoforms',}int_list_fields={'references','isoforms',}field_synonyms={'organism':'ncbi_tax_id','tfregulons_level':'dorothea_level','tfregulons_curated':'dorothea_curated','tfregulons_chipseq':'dorothea_chipseq','tfregulons_tfbs':'dorothea_tfbs','tfregulons_coexp':'dorothea_coexp','sources':'resources','databases':'resources',}args_reference={'interactions':{'header':None,'format':{'json','tab','text','tsv','table'},'license':{'ignore','academic','non_profit','nonprofit','for_profit','forprofit','commercial',},'password':None,'limit':None,'datasets':{'omnipath','tfregulons','dorothea','collectri','tf_target','tf_mirna','lncrna_mrna','kinaseextra','ligrecextra','pathwayextra','mirnatarget','small_molecule',},'types':{'post_translational','transcriptional','post_transcriptional','mirna_transcriptional','lncrna_post_transcriptional','small_molecule_protein',},'sources':None,'resources':None,'databases':None,'targets':None,'partners':None,'genesymbols':_const.BOOLEAN_VALUES,'evidences':None,'extra_attrs':None,'fields':{'entity_type','references','sources','tfregulons_level','tfregulons_curated','tfregulons_chipseq','tfregulons_tfbs','tfregulons_coexp','dorothea_level','dorothea_curated','dorothea_chipseq','dorothea_tfbs','dorothea_coexp','type','ncbi_tax_id','databases','resources','organism','curation_effort','datasets','extra_attrs','evidences',},'tfregulons_levels':{'A','B','C','D','E'},'tfregulons_methods':{'curated','chipseq','coexp','tfbs',},'dorothea_levels':{'A','B','C','D','E'},'dorothea_methods':{'curated','chipseq','coexp','tfbs',},'organisms':{'9606','10090','10116',},'source_target':{'AND','OR','and','or',},'directed':_const.BOOLEAN_VALUES,'signed':_const.BOOLEAN_VALUES,'loops':_const.BOOLEAN_VALUES,'entity_types':{'protein','complex','mirna','lncrna','small_molecule','drug','metabolite','lipid',},},'enzsub':{'header':None,'format':{'json','tab','text','tsv','table',},'license':{'ignore','academic','non_profit','nonprofit','for_profit','forprofit','commercial',},'password':None,'limit':None,'enzymes':None,'substrates':None,'partners':None,'genesymbols':_const.BOOLEAN_VALUES,'organisms':{'9606','10090','10116',},'databases':None,'resources':None,'residues':None,'modification':None,'types':None,'fields':{'sources','references','ncbi_tax_id','organism','databases','resources','isoforms','curation_effort',},'enzyme_substrate':{'AND','OR','and','or',}},'annotations':{'header':None,'format':{'json','tab','text','tsv','table',},'license':{'ignore','academic','non_profit','nonprofit','for_profit','forprofit','commercial',},'password':None,'limit':None,'databases':None,'resources':None,'proteins':None,'fields':None,'genesymbols':_const.BOOLEAN_VALUES,'entity_types':{'protein','complex','mirna','lncrna','small_molecule','drug','metabolite','lipid',},},'annotations_summary':{'header':None,'format':{'json','tab','text','tsv','table',},'databases':None,'resources':None,'fields':None,'cytoscape':_const.BOOLEAN_VALUES,},'intercell':{'header':None,'format':{'json','tab','text','tsv','table',},'license':{'ignore','academic','non_profit','nonprofit','for_profit','forprofit','commercial',},'password':None,'limit':None,'scope':{'specific','generic',},'aspect':{'functional','locational',},'source':{'resource_specific','composite',},'categories':None,'databases':None,'resources':None,'parent':None,'proteins':None,'fields':None,'entity_types':{'protein','complex','mirna','lncrna','small_molecule','drug','metabolite','lipid',},'transmitter':_const.BOOLEAN_VALUES,'receiver':_const.BOOLEAN_VALUES,'trans':_const.BOOLEAN_VALUES,'rec':_const.BOOLEAN_VALUES,'secreted':_const.BOOLEAN_VALUES,'plasma_membrane_peripheral':_const.BOOLEAN_VALUES,'plasma_membrane_transmembrane':_const.BOOLEAN_VALUES,'sec':_const.BOOLEAN_VALUES,'pmp':_const.BOOLEAN_VALUES,'pmtm':_const.BOOLEAN_VALUES,'causality':{'transmitter','trans','receiver','rec','both'},'topology':{'secreted','sec','plasma_membrane_peripheral','pmp','plasma_membrane_transmembrane','pmtm',},},'intercell_summary':{'header':None,'format':{'json','tab','text','tsv','table',},'scope':{'specific','generic',},'aspect':{'functional','locational',},'source':{'resource_specific','generic',},'categories':None,'resources':None,'databases':None,'parent':None,'fields':None,'transmitter':_const.BOOLEAN_VALUES,'receiver':_const.BOOLEAN_VALUES,'trans':_const.BOOLEAN_VALUES,'rec':_const.BOOLEAN_VALUES,'secreted':_const.BOOLEAN_VALUES,'plasma_membrane_peripheral':_const.BOOLEAN_VALUES,'plasma_membrane_transmembrane':_const.BOOLEAN_VALUES,'sec':_const.BOOLEAN_VALUES,'pmp':_const.BOOLEAN_VALUES,'pmtm':_const.BOOLEAN_VALUES,},'complexes':{'header':None,'format':{'json','tab','text','tsv','table',},'license':{'ignore','academic','non_profit','nonprofit','for_profit','forprofit','commercial',},'password':None,'limit':None,'databases':None,'resources':None,'proteins':None,'fields':None,},'resources':{'license':{'ignore','academic','non_profit','nonprofit','for_profit','forprofit','commercial',},'format':{'json',},'datasets':{'interactions','interaction','network','enzsub','enz_sub','enzyme-substrate','annotations','annotation','annot','intercell','complex','complexes',},'subtypes':None,},'queries':{'format':{'tab','text','tsv','table','json',},},}query_type_synonyms={'interactions':'interactions','interaction':'interactions','network':'interactions','enz_sub':'enzsub','enz-sub':'enzsub','ptms':'enzsub','ptm':'enzsub','enzyme-substrate':'enzsub','enzyme_substrate':'enzsub','annotations':'annotations','annotation':'annotations','annot':'annotations','intercell':'intercell','intercellular':'intercell','inter_cell':'intercell','inter-cell':'intercell','complex':'complexes','complexes':'complexes',}datasets_={'omnipath','tfregulons','dorothea','collectri','tf_target','kinaseextra','ligrecextra','pathwayextra','mirnatarget','tf_mirna','lncrna_mrna','small_molecule',}dorothea_methods={'curated','coexp','chipseq','tfbs'}dataset2type={'omnipath':'post_translational','tfregulons':'transcriptional','dorothea':'transcriptional','collectri':'transcriptional','tf_target':'transcriptional','kinaseextra':'post_translational','ligrecextra':'post_translational','pathwayextra':'post_translational','mirnatarget':'post_transcriptional','tf_mirna':'mirna_transcriptional','lncrna_mrna':'lncrna_post_transcriptional','small_molecule':'small_molecule_protein',}interaction_fields={'references','sources','dorothea_level','dorothea_curated','dorothea_chipseq','dorothea_tfbs','dorothea_coexp','tfregulons_level','tfregulons_curated','tfregulons_chipseq','tfregulons_tfbs','tfregulons_coexp','type','ncbi_tax_id','databases','organism','curation_effort','resources','entity_type','datasets','extra_attrs','evidences',}enzsub_fields={'references','sources','databases','isoforms','organism','ncbi_tax_id','curation_effort','resources',}default_input_files={'interactions':'omnipath_webservice_interactions.tsv','enzsub':'omnipath_webservice_enz_sub.tsv','annotations':'omnipath_webservice_annotations.tsv','complexes':'omnipath_webservice_complexes.tsv','intercell':'omnipath_webservice_intercell.tsv',}default_dtypes=collections.defaultdict(dict,interactions={'source':'category','target':'category','source_genesymbol':'category','target_genesymbol':'category','is_directed':'int8','is_stimulation':'int8','is_inhibition':'int8','consensus_direction':'int8','consensus_stimulation':'int8','consensus_inhibition':'int8','sources':'category','references':'category','dorothea_curated':'category','dorothea_chipseq':'category','dorothea_tfbs':'category','dorothea_coexp':'category','dorothea_level':'category','type':'category','ncbi_tax_id_source':'int16','ncbi_tax_id_target':'int16','entity_type_source':'category','entity_type_target':'category','curation_effort':'int16','extra_attrs':'category','evidences':'category',},annotations={'uniprot':'category','genesymbol':'category','entity_type':'category','source':'category','label':'category','value':'category','record_id':'uint32',},enzsub={'enzyme':'category','substrate':'category','enzyme_genesymbol':'category','substrate_genesymbol':'category','isoforms':'category','residue_type':'category','residue_offset':'uint16','modification':'category','sources':'category','references':'category','ncbi_tax_id':'int16','curation_effort':'int32',},complexes={'name':'category','stoichiometry':'category','sources':'category','references':'category','identifiers':'category',},intercell={'category':'category','database':'category','uniprot':'category','genesymbol':'category','parent':'category','aspect':'category','scope':'category','source':'category','entity_type':'category','consensus_score':'uint16','transmitter':'bool','receiver':'bool','secreted':'bool','plasma_membrane_transmembrane':'bool','plasma_membrane_peripheral':'bool',})# the annotation attributes served for the cytoscape appcytoscape_attributes={('Zhong2015','type'),('MatrixDB','mainclass'),('Matrisome',('mainclass','subclass','subsubclass')),# ('TFcensus', 'in TFcensus'),('Locate',('location','cls')),('Phosphatome',('family','subfamily',#'has_protein_substrates',)),('CancerSEA','state'),('GO_Intercell','mainclass'),('Adhesome','mainclass'),('SignaLink3','pathway'),('HPA_secretome',('mainclass',#'secreted',)),('OPM',('membrane','family',#'transmembrane',)),('KEGG','pathway'),#(#'CellPhoneDB',#(## 'receptor',## 'peripheral',## 'secreted',## 'transmembrane',## 'receptor_class',## 'secreted_class',#)#),('kinase.com',('group','family','subfamily')),('Membranome',('membrane',)),#('CSPA', 'in CSPA'),#('MSigDB', 'geneset'),#('Integrins', 'in Integrins'),('HGNC','mainclass'),('CPAD',('pathway','effect_on_cancer','cancer',)),('Signor','pathway'),('Ramilowski2015','mainclass'),('HPA_subcellular','location'),#('DisGeNet', 'disease'),('Surfaceome',('mainclass','subclasses')),('IntOGen','role'),('HPMR',('role','mainclass','subclass','subsubclass')),#('CancerGeneCensus',#(##'hallmark',##'somatic',##'germline',#'tumour_types_somatic',#'tumour_types_germline',#)#),#('DGIdb', 'category'),('ComPPI','location'),('Exocarta','vesicle'),('Vesiclepedia','vesicle'),('Ramilowski_location','location'),('LRdb',('role','cell_type')),}
[docs]def__init__(self,input_files=None,only_tables=None,exclude_tables=None,):""" Server based on ``pandas`` data frames. :param dict input_files: Paths to tables exported by the ``pypath.websrvtab`` module. """session_mod.Logger.__init__(self,name='server')self._log('TableServer starting up.')self.input_files=copy.deepcopy(self.default_input_files)self.input_files.update(input_filesor{})self.data={}self.to_load=(self.data_query_types-common.to_set(exclude_tables)ifonly_tablesisNoneelsecommon.to_set(only_tables))self._log('Datasets to load: %s.'%(', '.join(sorted(self.to_load))))self._read_tables()self._preprocess_interactions()self._preprocess_enzsub()self._preprocess_annotations()self._preprocess_complexes()self._preprocess_intercell()self._update_resources()BaseServer.__init__(self)self._log('TableServer startup ready.')
def_read_tables(self):self._log('Loading data tables.')forname,fnameiniteritems(self.input_files):ifnamenotinself.to_load:continuefname_gz=f'{fname}.gz'fname=fname_gzifos.path.exists(fname_gz)elsefnameself._log('Loading dataset `%s` from file `%s`.'%(name,fname))ifnotos.path.exists(fname):self._log('Missing table: `%s`.'%fname)continuedtype=self.default_dtypes[name]self.data[name]=pd.read_csv(fname,sep='\t',index_col=False,dtype=dtype,)self._log('Table `%s` loaded from file `%s`.'%(name,fname))def_network(self,req):hdr=['nodes','edges','is_directed','sources']tbl=self.data['network'].fieldval=dict(zip(tbl.field,tbl.value))ifb'format'inreq.argsandreq.args[b'format']==b'json':returnjson.dumps(val)else:return'%s\n%s'%('\t'.join(hdr),'\t'.join([str(val[h])forhinhdr]))def_preprocess_interactions(self):if'interactions'notinself.data:returnself._log('Preprocessing interactions.')tbl=self.data['interactions']tbl['set_sources']=pd.Series([set(s.split(';'))forsintbl.sources])tbl['set_dorothea_level']=pd.Series([set(s.split(';'))ifnotpd.isnull(s)elseset([])forsintbl.dorothea_level])def_preprocess_enzsub(self):if'enzsub'notinself.data:returnself._log('Preprocessing enzyme-substrate relationships.')tbl=self.data['enzsub']tbl['set_sources']=pd.Series([set(s.split(';'))forsintbl.sources])def_preprocess_complexes(self):if'complexes'notinself.data:returnself._log('Preprocessing complexes.')tbl=self.data['complexes']tbl=tbl[~tbl.components.isna()]withignore_pandas_copywarn():tbl['set_sources']=[set(s.split(';'))forsintbl.sources]tbl['set_proteins']=[set(c.split('_'))forcintbl.components]self.data['complexes']=tbldef_preprocess_annotations_old(self):if'annotations'notinself.data:returnrenum=re.compile(r'[-\d\.]+')def_agg_values(vals):result=('#'.join(sorted(set(str(ii)foriiinvals)))ifnotall(isinstance(i,(int,float))or(isinstance(i,str)andiand(iisNoneorrenum.match(i)))foriinvals)else'<numeric>')returnresultself._log('Preprocessing annotations.')self.data['annotations_summary']=self.data['annotations'].groupby(['source','label'],).agg({'value':_agg_values}).reset_index(drop=False)def_preprocess_annotations(self):if'annotations'notinself.data:returnrenum=re.compile(r'[-\d\.]+')self._log('Preprocessing annotations.')values_by_key=collections.defaultdict(set)# we need to do it this way as we are memory limited on the server# and pandas groupby is very memory intensiveforrowinself.data['annotations'].itertuples():value=('<numeric>'if((notisinstance(row.value,bool)andisinstance(row.value,(int,float)))orrenum.match(row.value))elsestr(row.value))values_by_key[(row.source,row.label)].add(value)forvalsinvalues_by_key.values():iflen(vals)>1:vals.discard('<numeric>')vals.discard('')vals.discard('nan')self.data['annotations_summary']=pd.DataFrame(list((source,label,'#'.join(sorted(values)))for(source,label),valuesiniteritems(values_by_key)),columns=['source','label','value'],)def_preprocess_intercell(self):if'intercell'notinself.data:returnself._log('Preprocessing intercell data.')tbl=self.data['intercell']tbl.drop('full_name',axis=1,inplace=True,errors='ignore')self.data['intercell_summary']=tbl.filter(['category','parent','database'],).drop_duplicates()def_update_resources(self):self._log('Updating resource information.')self._resources_dict=collections.defaultdict(dict)res_ctrl=resources_mod.get_controller()forquery_typeinself.data_query_types:ifquery_typenotinself.data:continuetbl=self.data[query_type]# finding out what is the name of the column with the resources# as this is different across the tablesforcolname,argnamein(('database','databases'),('sources','databases'),('source','databases'),('category','categories')):ifcolnameintbl.columns:break# collecting all resource namesvalues=sorted(set(itertools.chain(*(val.split(';')forvalingetattr(tbl,colname)))))fordbinvalues:if'license'notinself._resources_dict[db]:license=res_ctrl.license(db)iflicenseisNone:msg='No license for resource `%s`.'%str(db)self._log(msg)raiseRuntimeError(msg)license_data=license.featureslicense_data['name']=license.namelicense_data['full_name']=license.full_nameself._resources_dict[db]['license']=license_dataif'queries'notinself._resources_dict[db]:self._resources_dict[db]['queries']={}ifquery_typenotinself._resources_dict[db]['queries']:ifquery_type=='interactions':datasets=set()fordatasetinself.datasets_:ifdatasetnotintbl.columns:continueforin_dataset,resourcesinzip(getattr(tbl,dataset),tbl.set_sources,):ifin_datasetanddbinresources:datasets.add(dataset)breakself._resources_dict[db]['queries'][query_type]={'datasets':sorted(datasets),}elifquery_type=='intercell':tbl_db=tbl[(tbl.database==db)&(tbl.scope=='generic')]self._resources_dict[db]['queries'][query_type]={'generic_categories':sorted(set(tbl_db.category)),}else:self._resources_dict[db]['queries'][query_type]={}self.args_reference[query_type][argname]=valuesself._resources_dict=dict(self._resources_dict)self._log('Finished updating resource information.')def_check_args(self,req):result=[]argname=req.postpath[0]ref=(self.args_reference['resources']ifargname=='databases'elseself.args_reference[argname])forarg,valiniteritems(req.args):arg=arg.decode('utf-8')ifarginref:ifnotref[arg]ornotval:continueval=({val[0]}iftype(val[0])isintelseset(val[0].decode('utf-8').split(',')))unknowns=val-set(ref[arg])ifunknowns:result.append(' ==> Unknown values for argument `%s`: `%s`'%(arg,', '.join(str(u)foruinunknowns)))else:result.append(' ==> Unknown argument: `%s`'%arg)req.args[b'header']=self._parse_arg(req.args[b'header'])ifresult:return('Something is not entirely good:\n%s\n\n''Please check the examples at\n''https://github.com/saezlab/pypath\n''and\n''https://github.com/saezlab/DoRothEA\n''If you still experiencing issues contact us at\n''https://github.com/saezlab/pypath/issues'''%'\n'.join(result))defqueries(self,req):query_type=(req.postpath[1]iflen(req.postpath)>1else'interactions')query_type=self._query_type(query_type)query_param=(req.postpath[2]iflen(req.postpath)>2elseNone)ifquery_typeinself.args_reference:result=dict((k,sorted(v)ifisinstance(v,_const.LIST_LIKE)elsev)fork,vinself.args_reference[query_type].items())ifquery_paramisnotNoneandquery_paraminresult:result={query_param:result[query_param]}else:result={}result[query_type]=('No possible arguments defined for''query `%s` or no such query available.'%query_type)result=self._dict_set_to_list(result)ifb'format'inreq.argsandreq.args[b'format'][0]==b'json':returnjson.dumps(result)else:return'argument\tvalues\n%s'%'\n'.join('%s\t%s'%(k,';'.join(v)ifisinstance(v,(list,set,tuple))elsestr(v))fork,viniteritems(result))@classmethoddef_dict_set_to_list(cls,dct):returndict((key,(sorted(val)ifisinstance(val,_const.LIST_LIKE)elsecls._dict_set_to_list(val)ifisinstance(val,dict)elseval))forkey,valiniteritems(dct))defdatabases(self,req):query_type=(req.postpath[1]iflen(req.postpath)>1else'interactions')query_type=self._query_type(query_type)datasets=(set(req.postpath[2].split(','))iflen(req.postpath)>2elseNone)tbl=(self.data[query_type]ifquery_typeinself.dataelseself.data['interactions'])# filter for datasetsifquery_type=='interactions':ifdatasetsisnotNone:tbl=tbl.loc[tbl.type.isin(datasets)]else:datasets=self._get_datasets()result={}fordatasetindatasets:result[dataset]=sorted(set.union(*tbl[tbl.type==dataset].set_sources))else:result={}result['*']=sorted(set.union(*tbl.set_sources))ifb'format'inreq.argsandreq.args[b'format'][0]==b'json':returnjson.dumps(result)else:return'dataset\tresources\n%s'%'\n'.join('%s\t%s'%(k,';'.join(v))fork,viniteritems(result))def_get_datasets(self):returnlist(self.data['interactions'].type.unique())defdatasets(self,req):query_type=(req.postpath[1]iflen(req.postpath)>1else'interactions')ifquery_type=='interactions':result=self._get_datasets()else:result=[]ifb'format'inreq.argsandreq.args[b'format'][0]==b'json':returnjson.dumps(result)else:return';'.join(result)definteractions(self,req,datasets={'omnipath'},databases=None,dorothea_levels={'A','B'},organisms={9606},source_target='OR',):bad_req=self._check_args(req)ifbad_req:returnbad_reqhdr=['source','target','is_directed','is_stimulation','is_inhibition','consensus_direction','consensus_stimulation','consensus_inhibition',]ifb'source_target'inreq.args:source_target=(req.args[b'source_target'][0].decode('utf-8').upper())# changes the old, "tfregulons" names to new "dorothea"self._tfregulons_dorothea(req)ifb'databases'inreq.args:req.args[b'resources']=req.args[b'databases']args={}forargin('datasets','types','sources','targets','partners','resources','organisms','dorothea_levels','dorothea_methods',):args[arg]=self._args_set(req,arg)# here adjust on the defaults otherwise we serve empty# response by defaultifnotargs['types']:args['datasets']=args['datasets']ordatasets# keep only valid dataset namesargs['datasets']=args['datasets']&self.datasets_args['organisms']=set(int(t)fortinargs['organisms']ift.isdigit())args['organisms']=args['organisms']ororganisms# do not allow impossible values# those would result KeyError laterargs['dorothea_levels']=(args['dorothea_levels']ordorothea_levels)args['dorothea_methods']=(args['dorothea_methods']&self.dorothea_methods)# provide genesymbols: yes or noif(b'genesymbols'inreq.argsandself._parse_arg(req.args[b'genesymbols'])):genesymbols=Truehdr.insert(2,'source_genesymbol')hdr.insert(3,'target_genesymbol')else:genesymbols=Falseself._log('Processed arguments: [%s].'%common.dict_str(args))# starting from the entire datasettbl=self.data['interactions']# filter by typeifargs['types']:tbl=tbl.loc[tbl.type.isin(args['types'])]# if partners provided those will overwrite# sources and targetsargs['sources']=args['sources']orargs['partners']args['targets']=args['targets']orargs['partners']# then we filter by source and target# which matched against both standard names# and gene symbolsifargs['sources']andargs['targets']andsource_target=='OR':tbl=tbl.loc[tbl.target.isin(args['targets'])|tbl.target_genesymbol.isin(args['targets'])|tbl.source.isin(args['sources'])|tbl.source_genesymbol.isin(args['sources'])]else:ifargs['sources']:tbl=tbl.loc[tbl.source.isin(args['sources'])|tbl.source_genesymbol.isin(args['sources'])]ifargs['targets']:tbl=tbl.loc[tbl.target.isin(args['targets'])|tbl.target_genesymbol.isin(args['targets'])]# filter by datasetsifargs['datasets']:tbl=tbl.query(' or '.join(args['datasets']))# filter by organismtbl=tbl.loc[tbl.ncbi_tax_id_source.isin(args['organisms'])|tbl.ncbi_tax_id_target.isin(args['organisms'])]dorothea_included=('dorothea'inargs['datasets']orany(res.endswith('DoRothEA')forresinargs['resources'])or('transcriptional'inargs['types']andnotargs['datasets']))# filter by DoRothEA confidence levelsifdorothea_includedandargs['dorothea_levels']:tbl=tbl.loc[self._dorothea_dataset_filter(tbl,args)|[bool(levels&args['dorothea_levels'])forlevelsintbl.set_dorothea_level]]# filter by databasesifargs['resources']:tbl=tbl.loc[[bool(sources&args['resources'])forsourcesintbl.set_sources]]# filtering for entity typesifb'entity_types'inreq.args:entity_types=self._args_set(req,'entity_types')iflen(entity_types)==1and'protein'inentity_types:# pandas is awful:tbl=tbl.loc[np.logical_and(tbl.entity_type_source.astype('string')=='protein',tbl.entity_type_target.astype('string')=='protein',)]else:tbl=tbl.loc[tbl.entity_type_source.isin(entity_types)|tbl.entity_type_target.isin(entity_types)]# filtering by DoRothEA methodsifdorothea_includedandargs['dorothea_methods']:q=['dorothea_%s'%mforminargs['dorothea_methods']]tbl=tbl.loc[self._dorothea_dataset_filter(tbl,args)|tbl[q].any(1)]# filter directed & signedif(b'directed'notinreq.argsorself._parse_arg(req.args[b'directed'])):tbl=tbl.loc[tbl.is_directed==1]if(b'signed'inreq.argsandself._parse_arg(req.args[b'signed'])):tbl=tbl.loc[np.logical_or(tbl.is_stimulation==1,tbl.is_inhibition==1)]# loops: remove by defaultif(b'loops'notinreq.argsornotself._parse_arg(req.args[b'loops'])):# pandas is a disaster:tbl=tbl.loc[tbl.source.astype('string')!=tbl.target.astype('string')]req.args[b'fields']=req.args[b'fields']or[b'']_fields=[fforfinreq.args[b'fields'][0].decode('utf-8').split(',')iffinself.interaction_fields]forfin(b'evidences',b'extra_attrs'):iffinreq.uriandfnotinreq.args[b'fields'][0]:_fields.append(f.decode('utf-8'))forfin_fields:iff=='ncbi_tax_id'orf=='organism':hdr.append('ncbi_tax_id_source')hdr.append('ncbi_tax_id_target')eliff=='entity_type':hdr.append('entity_type_source')hdr.append('entity_type_target')eliffin{'databases','resources'}:hdr.append('sources')eliff=='datasets':hdr.extend(set(tbl.columns)&self.args_reference['interactions']['datasets']&args['datasets'])else:hdr.append(f)license=self._get_license(req)tbl=self._filter_by_license_interactions(tbl,license)tbl=tbl.loc[:,hdr]returnself._serve_dataframe(tbl,req)@classmethoddef_dataset_included(cls,dataset:str,args:dict)->bool:return(datasetinargs['datasets']or(notargs['datasets']andcls.dataset2type.get(dataset,None)inargs['types']))@classmethoddef_dorothea_dataset_filter(cls,tbl:pd.DataFrame,args:dict):return((# if the tf_target dataset is requested# we need to serve it including the parts which# don't fit the filters belowcls._dataset_included('tf_target',args)&tbl.tf_target)|(cls._dataset_included('collectri',args)&tbl.collectri)|(tbl.type!='transcriptional'))def_tfregulons_dorothea(self,req):forargin(b'datasets',b'fields'):ifarginreq.args:req.args[arg]=[it.replace(b'tfregulons',b'dorothea')foritinreq.args[arg]]forpostfixin(b'levels',b'methods'):key=b'tfregulons_%s'%postfixnew_key=b'dorothea_%s'%postfixifkeyinreq.argsandnew_keynotinreq.args:req.args[new_key]=req.args[key]_=req.args.pop(key)defenzsub(self,req,organisms={9606},enzyme_substrate='OR'):bad_req=self._check_args(req)ifbad_req:returnbad_reqhdr=['enzyme','substrate','residue_type','residue_offset','modification']ifb'enzyme_substrate'inreq.args:enzyme_substrate=(req.args[b'enzyme_substrate'][0].decode('utf-8').upper())ifb'databases'inreq.args:req.args[b'resources']=req.args[b'databases']args={}forargin('enzymes','substrates','partners','resources','organisms','types','residues'):args[arg]=self._args_set(req,arg)args['organisms']=set(int(t)fortinargs['organisms']ift.isdigit())args['organisms']=args['organisms']ororganisms# provide genesymbols: yes or noif(b'genesymbols'inreq.argsandself._parse_arg(req.args[b'genesymbols'])):genesymbols=Truehdr.insert(2,'enzyme_genesymbol')hdr.insert(3,'substrate_genesymbol')else:genesymbols=False# starting from the entire datasettbl=self.data['enzsub']# filter by typeifargs['types']:tbl=tbl.loc[tbl.modification.isin(args['types'])]# if partners provided those will overwrite# enzymes and substratesargs['enzymes']=args['enzymes']orargs['partners']args['substrates']=args['substrates']orargs['partners']# then we filter by enzyme and substrate# which matched against both standard names# and gene symbolsif(args['enzymes']andargs['substrates']andenzyme_substrate=='OR'):tbl=tbl.loc[tbl.substrate.isin(args['substrates'])|tbl.substrate_genesymbol.isin(args['substrates'])|tbl.enzyme.isin(args['enzymes'])|tbl.enzyme_genesymbol.isin(args['enzymes'])]else:ifargs['enzymes']:tbl=tbl.loc[tbl.enzyme.isin(args['enzymes'])|tbl.enzyme_genesymbol.isin(args['enzymes'])]ifargs['substrates']:tbl=tbl.loc[tbl.substrate.isin(args['substrates'])|tbl.substrate_genesymbol.isin(args['substrates'])]# filter by organismtbl=tbl.loc[tbl.ncbi_tax_id.isin(args['organisms'])]# filter by databasesifargs['resources']:tbl=tbl.loc[[bool(args['resources']&sources)forsourcesintbl.set_sources]]ifreq.args[b'fields']:_fields=[fforfinreq.args[b'fields'][0].decode('utf-8').split(',')iffinself.enzsub_fields]forfin_fields:iff=='ncbi_tax_id'orf=='organism':hdr.append('ncbi_tax_id')eliffin{'databases','resources'}:hdr.append('sources')else:hdr.append(f)license=self._get_license(req)tbl=self._filter_by_license_interactions(tbl,license)tbl=tbl.loc[:,hdr]returnself._serve_dataframe(tbl,req)defptms(self,req):req.postpath[0]='enzsub'returnself.enzsub(req)defenz_sub(self,req):req.postpath[0]='enzsub'returnself.enzsub(req)defannotations(self,req):bad_req=self._check_args(req)ifbad_req:returnbad_reqifb'databases'inreq.args:req.args[b'resources']=req.args[b'databases']if(notsettings.get('server_annotations_full_download')andnotb'resources'inreq.argsandnotb'proteins'inreq.args):return('Downloading the entire annotations database by the REST ''API is not allowed because of its huge size (>1GB). ''We recommend to query a set of proteins or a few ''resources, depending on your interest. ''You can always download the full database from ''https://archive.omnipathdb.org/''omnipath_webservice_annotations__recent.tsv')# starting from the entire datasettbl=self.data['annotations']hdr=tbl.columns# filtering for resourcesifb'resources'inreq.args:resources=self._args_set(req,'resources')tbl=tbl.loc[tbl.source.isin(resources)]# filtering for entity typesifb'entity_types'inreq.args:entity_types=self._args_set(req,'entity_types')tbl=tbl.loc[tbl.entity_type.isin(entity_types)]# filtering for proteinsifb'proteins'inreq.args:proteins=self._args_set(req,'proteins')tbl=tbl.loc[tbl.uniprot.isin(proteins)|tbl.genesymbol.isin(proteins)]# provide genesymbols: yes or noif(b'genesymbols'inreq.argsandself._parse_arg(req.args[b'genesymbols'])):genesymbols=Truehdr.insert(1,'genesymbol')else:genesymbols=Falselicense=self._get_license(req)tbl=self._filter_by_license_annotations(tbl,license)tbl=tbl.loc[:,hdr]returnself._serve_dataframe(tbl,req)defannotations_summary(self,req):bad_req=self._check_args(req)ifbad_req:returnbad_reqifb'databases'inreq.args:req.args[b'resources']=req.args[b'databases']# starting from the entire datasettbl=self.data['annotations_summary']hdr=tbl.columns# filtering for resourcesifb'resources'inreq.args:resources=self._args_set(req,'resources')tbl=tbl.loc[tbl.source.isin(resources)]if(b'cytoscape'inreq.argsandself._parse_arg(req.args[b'cytoscape'])):cytoscape=Trueelse:cytoscape=Falsetbl=tbl.loc[:,hdr]ifcytoscape:tbl=tbl.set_index(['source','label'],drop=False)cytoscape_keys={(source,label)forsource,labelsinself.cytoscape_attributesforlabelin(labelsifisinstance(labels,tuple)else(labels,))}&set(tbl.index)tbl=tbl.loc[list(cytoscape_keys)]returnself._serve_dataframe(tbl,req)defintercell(self,req):bad_req=self._check_args(req)ifbad_req:returnbad_reqifb'databases'inreq.args:req.args[b'resources']=req.args[b'databases']# starting from the entire datasettbl=self.data['intercell']hdr=tbl.columns# filtering for category typesforvarin('aspect','source','scope','transmitter','receiver','parent','resources',):ifvar.encode('ascii')inreq.args:values=self._args_set(req,var)ifvarin{'resources','databases'}:var='database'tbl=tbl.loc[getattr(tbl,var).isin(values)]for(_long,short)in(('transmitter','trans'),('receiver','rec'),('secreted','sec'),('plasma_membrane_peripheral','pmp'),('plasma_membrane_transmembrane','pmtm'),):this_arg=None_long_b=_long.encode('ascii')short_b=short.encode('ascii')if_long_binreq.args:this_arg=self._parse_arg(req.args[_long_b])elifshort_binreq.args:this_arg=self._parse_arg(req.args[short_b])ifthis_argisnotNone:tbl=tbl.loc[getattr(tbl,_long)==this_arg]ifb'causality'inreq.args:causality=self._args_set(req,'causality')trans=causality&{'transmitter','trans','both'}rec=causality&{'receiver','rec','both'}tbl=(tbl.loc[tbl.transmitter|tbl.receiver]iftransandrecelsetbl.loc[tbl.transmitter]iftranselsetbl.loc[tbl.receiver]ifrecelsetbl)ifb'topology'inreq.args:topology=self._args_set(req,'topology')query=' or '.join(colnameforenabled,colnamein((topology&{'secreted','sec'},'secreted'),(topology&{'plasma_membrane_peripheral','pmp'},'plasma_membrane_peripheral'),(topology&{'plasma_membrane_transmembrane','pmtm'},'plasma_membrane_transmembrane'))ifenabled)ifquery:tbl=tbl.query(query)# filtering for categoriesifb'categories'inreq.args:categories=self._args_set(req,'categories')tbl=tbl.loc[tbl.category.isin(categories)]# filtering for entity typesifb'entity_types'inreq.args:entity_types=self._args_set(req,'entity_types')tbl=tbl.loc[tbl.entity_type.isin(entity_types)]# filtering for proteinsifb'proteins'inreq.args:proteins=self._args_set(req,'proteins')tbl=tbl.loc[np.logical_or(tbl.uniprot.isin(proteins),tbl.genesymbol.isin(proteins),)]license=self._get_license(req)tbl=self._filter_by_license_intercell(tbl,license)tbl=tbl.loc[:,hdr]returnself._serve_dataframe(tbl,req)defintercell_summary(self,req):bad_req=self._check_args(req)ifbad_req:returnbad_reqifb'databases'inreq.args:req.args[b'resources']=req.args[b'databases']# starting from the entire datasettbl=self.data['intercell_summary']hdr=tbl.columns# filtering for category typesforvarin('aspect','source','scope','transmitter','receiver','parent','resources',):ifvar.encode('ascii')inreq.args:values=self._args_set(req,var)tbl=tbl.loc[getattr(tbl,var).isin(values)]# filtering for categoriesifb'categories'inreq.args:categories=self._args_set(req,'categories')tbl=tbl.loc[tbl.category.isin(categories)]tbl=tbl.loc[:,hdr]returnself._serve_dataframe(tbl,req)defcomplexes(self,req):bad_req=self._check_args(req)ifbad_req:returnbad_reqifb'databases'inreq.args:req.args[b'resources']=req.args[b'databases']# starting from the entire datasettbl=self.data['complexes']hdr=list(tbl.columns)hdr.remove('set_sources')hdr.remove('set_proteins')# filtering for resourcesifb'resources'inreq.args:resources=self._args_set(req,'resources')tbl=tbl.loc[[bool(sources&resources)forsourcesintbl.set_sources]]# filtering for proteinsifb'proteins'inreq.args:proteins=self._args_set(req,'proteins')tbl=tbl.loc[[bool(this_proteins&proteins)forthis_proteinsintbl.set_proteins]]license=self._get_license(req)tbl=self._filter_by_license_complexes(tbl,license)tbl=tbl.loc[:,hdr]returnself._serve_dataframe(tbl,req)defresources(self,req):datasets=({self._query_type(dataset.decode('ascii'))fordatasetinreq.args[b'datasets']}ifb'datasets'inreq.argselseNone)res_ctrl=resources_mod.get_controller()license=self._get_license(req)returnjson.dumps(dict((k,v)fork,viniteritems(self._resources_dict)if(res_ctrl.license(k).enables(license)and(notdatasetsordatasets&set(v['datasets'].keys())))))@staticmethoddef_get_license(req):returnreq.args[b'license'][0].decode('utf-8')@classmethoddef_filter_by_license_complexes(cls,tbl,license):returncls._filter_by_license(tbl=tbl,license=license,res_col='sources',simple=False,prefix_col='identifiers',)@classmethoddef_filter_by_license_interactions(cls,tbl,license):returncls._filter_by_license(tbl=tbl,license=license,res_col='sources',simple=False,prefix_col='references',)@classmethoddef_filter_by_license_annotations(cls,tbl,license):returncls._filter_by_license(tbl=tbl,license=license,res_col='source',simple=True,)@classmethoddef_filter_by_license_intercell(cls,tbl,license):returncls._filter_by_license(tbl=tbl,license=license,res_col='database',simple=True,)@staticmethoddef_filter_by_license(tbl,license,res_col,simple=False,prefix_col=None,):deffilter_resources(res):res={rforrinresifres_ctrl.license(r).enables(license)}composite=[rforrinresifres_ctrl.license(r).name=='Composite']ifcomposite:composite_to_remove={comp_resforcomp_resincompositeifnotres_ctrl.secondary_resources(comp_res,True)&res}res=res-composite_to_removereturnresiflicense==LICENSE_IGNOREortbl.shape[0]==0:returntblres_ctrl=resources_mod.get_controller()_res_col=getattr(tbl,res_col)ifsimple:bool_idx=[res_ctrl.license(res).enables(license)forresin_res_col]else:_set_res_col=tbl.set_sources_res_to_keep=[filter_resources(ress)forressin_set_res_col]withignore_pandas_copywarn():tbl[res_col]=[';'.join(sorted(ress))forressin_res_to_keep]ifprefix_col:_prefix_col=getattr(tbl,prefix_col)_new_prefix_col=[';'.join(sorted(pref_resforpref_resinpref_ress.split(';')if(pref_res.split(':',maxsplit=1)[0]in_res_to_keep[i])))ifisinstance(pref_ress,str)elsepref_ressfori,pref_ressinenumerate(_prefix_col)]withignore_pandas_copywarn():tbl[prefix_col]=_new_prefix_colbool_idx=[bool(res)forresintbl[res_col]]tbl=tbl.loc[bool_idx]returntbl@classmethoddef_serve_dataframe(cls,tbl,req):ifb'limit'inreq.args:limit=req.args[b'limit'][0].decode('utf-8')iflimit.isdigit():limit=int(limit)tbl=tbl.head(limit)ifb'format'inreq.argsandreq.args[b'format'][0]==b'json':data_json=tbl.to_json(orient='records')# this is necessary because in the data frame we keep lists# as `;` separated strings but in json is nicer to serve# them as listsdata_json=json.loads(data_json)foriindata_json:fork,viniteritems(i):ifkincls.list_fields:i[k]=([(int(f)if(kincls.int_list_fieldsandf.isdigit())elsef)forfinv.split(';')]ifisinstance(v,str)else[])returnjson.dumps(data_json)else:returntbl.to_csv(sep='\t',index=False,header=bool(req.args[b'header']),chunksize=2e5,)@staticmethoddef_args_set(req,arg):arg=arg.encode('utf-8')return(set(req.args[arg][0].decode('utf-8').split(','))ifarginreq.argselseset())
[docs]def__init__(self,port,serverclass=TableServer,start=True,**kwargs):""" Runs a webserver serving a `PyPath` instance listening to a custom port. Args ----- :param int port: The port to listen to. :param str serverclass' The class implementing the server. :param **kwargs: Arguments for initialization of the server class. """self.port=port_log('Creating the server class.')self.server=serverclass(**kwargs)_log('Server class ready.')ifstart:_log('Starting the twisted server.')self.start()
defstart(self):self.site=TwistedWebSite(self.server)_log('Site created.')twisted_listen_tcp(self.port,self.site)_log('Server going to listen on port %u from now.'%self.port)twisted_run()