#!/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/#"""Here we define one class, the :py:class:`Interaction`` which provides arich API for representing and querying molecular interactions. Theinteractions serve as the building elements of the network and the:py:class:`pypath.network.Network` object largely relies on methodsof the :py:class:`Interaction`` objects."""from__future__importannotationsfromfuture.utilsimportiteritemsfromtypingimportLiteralimportimportlibasimpimportcollectionsimportoperatorimportitertoolsimportfunctoolsimportjsonimportpypath.core.evidenceaspypath_evidenceimportpypath.internals.resourceaspypath_resourceimportpypath.share.sessionassession_modimportpypath.share.commonascommonimportpypath.utils.mappingasmappingimportpypath.core.entityasentityimportpypath.core.attrsasattrs_modimportpypath.utils.orthologyasorthology_logger=session_mod.Logger(name='interaction')_log=_logger._logInteractionKey=collections.namedtuple('InteractionKey',['entity_a','entity_b',],)InteractionDataFrameRecord=collections.namedtuple('InteractionDataFrameRecord',['id_a','id_b','type_a','type_b','directed','effect','type','dmodel','sources','references',],)InteractionDataFrameRecord.__new__.__defaults__=(None,)*8
[docs]classInteraction(attrs_mod.AttributeHandler):""" Represents a unique pair of molecular entities interacting with each other. One :py:class:`Interaction` object might represent multiple interactions i.e. with different direction or effect or type (e.g. transcriptional regulation and post-translational regulation), each supported by different evidences. :arg str,pypath.entity.Entity a,b: The two interacting partners. If an :py:class:`pypath.entity.Entity` objects provided the other attributes (entity_type, id_type, taxon) will be ignored. :arg str id_type_a,id_type_b: The identifier types for partner ``a`` and ``b`` e.g. ``'uniprot'``. :arg str entity_type_a,entity_type_b: The types of the molecular entities ``a`` and ``b`` e.g. ``'protein'``. :arg int taxon_a,taxon_b: The NCBI Taxonomy Identifiers of partner ``a`` and ``b`` e.g. ``9606`` for human. :details: The arguments ``a`` and ``b`` will be assigned to the attribute ``a`` and ``b`` in an alphabetical order, hence it's possible that argument ``a`` becomes attribute ``b``. """__slots__=['a','b','a_b','b_a','nodes','key','evidences','direction','positive','negative','unknown_effect',]_get_methods={'datasets','entities','evidences','references','curation_effort','resource_names','resources','data_models','interaction_types','interactions','interactions_0','interactions_directed','interactions_undirected','interactions_non_directed','interactions_undirected_0','interactions_non_directed_0','interactions_signed','interactions_positive','interactions_negative','interactions_mutual','resources_via','resource_names_via',}_get_methods_autogen=('references','resources','resources_via','resource_names','resource_names_via','data_models','interaction_types','datasets',)_by_methods=('resource','reference','data_model','interaction_type','interaction_type_and_data_model','interaction_type_and_data_model_and_resource',)_count_methods={'references','resources','resources_via','resource_names_via','resource_names','curation_effort','entities','proteins','complexes','mirnas','interactions','interactions_0','interactions_directed','interactions_signed','interactions_positive','interactions_negative','data_models','interaction_types',}_get_method_signature=[('direction',None),('effect',None),('resources',None),('data_model',None),('interaction_type',None),('via',None),('references',None),]_degree_modes=('ALL','IN','OUT',)_degree_directions={'undirected':(None,None),'non_directed':(False,None),'directed':(True,None),'signed':(True,True),'positive':(True,'positive'),'negative':(True,'negative'),}_entity_types={'protein',('complex','complexes'),'mirna','lncrna',# ugly :((('small_molecule','drug','metabolite'),),None,}_entity_values={'identifiers','labels',None,}
[docs]defreload(self):""" Reloads the object from the module level. """modname=self.__class__.__module__evmodname=self.evidences.__class__.__module__enmodname=self.a.__class__.__module__mod=__import__(modname,fromlist=[modname.split('.')[0]])evmod=__import__(evmodname,fromlist=[evmodname.split('.')[0]])enmod=__import__(enmodname,fromlist=[enmodname.split('.')[0]])imp.reload(mod)imp.reload(evmod)imp.reload(enmod)new=getattr(mod,self.__class__.__name__)evsnew=getattr(evmod,'Evidences')evnew=getattr(evmod,'Evidence')ennew=getattr(enmod,'Entity')setattr(self,'__class__',new)forevsinitertools.chain((self.evidences,),self.direction.values(),self.positive.values(),self.negative.values(),self.unknown_effect.values(),):evs.__class__=evsnewforevinevs:ev.__class__=evnewself.a.__class__=ennewself.b.__class__=ennewself._generate_get_methods()self._generate_count_methods()self._generate_by_methods()
def_get_entity(self,identifier,id_type='uniprot',entity_type='protein',taxon=9606,):ifnotisinstance(identifier,entity.Entity):identifier=entity.Entity(identifier=identifier,id_type=id_type,entity_type=entity_type,taxon=taxon,)returnidentifierdef_check_nodes_key(self,nodes):"""Checks if *nodes* is contained in the edge. :arg list nodes: Or [tuple], contains the names of the nodes to be checked. :return: (*bool*) -- ``True`` if all elements in *nodes* are contained in the object :py:attr:`nodes` list. """returnnodes==self.a_bornodes==self.b_adef_check_direction_key(self,direction):""" Checks if *direction* is ``'undirected'`` or contains the nodes of the current edge. Used internally to check that *di* is a valid key for the object attributes declared on dictionaries. :arg tuple di: Or [str], key to be tested for validity. :return: (*bool*) -- ``True`` if *di* is ``'undirected'`` or a tuple of node names contained in the edge, ``False`` otherwise. """return(direction=='undirected'or(isinstance(direction,tuple)andself._check_nodes_key(direction)))defid_to_entity(self,identifier):return(self.aifself.a==identifierelseself.bifself.b==identifierelseNone)
[docs]defdirection_key(self,direction):""" The direction keys are tuples of `Entity` objects; this method creates these tuples from a tuple of strings. The two strings can be labels or identifiers. """ifdirection=='undirected':returndirectiondirection=tuple(map(self.id_to_entity,direction))return(directionifdirection==self.a_bordirection==self.b_aelseNone)
[docs]defadd_evidence(self,evidence,direction='undirected',effect=None,references=None,attrs=None,):""" Adds directionality information with the corresponding data source named. Modifies self attributes :py:attr:`dirs` and :py:attr:`sources`. :arg resource.NetworkResource,evidence.Evidence evidence: Either a ``pypath.evidence.Evidence`` object or a resource as ``pypath.resource.NetworkResource`` object. In the latter case the references can be provided in a separate argument. :arg tuple direction: Or [str], the directionality key for which the value on :py:attr:`dirs` has to be set ``True``. :arg int effect: The causal effect of the interaction. 1 or 'stimulation' corresponds to a stimulatory, -1 or 'inhibition' to an inhibitory while 0 to an unknown or neutral effect. :arg set,NoneType references: A set of references, used only if the resource have been provided as ``NetworkResource`` object. :arg dict attrs: Custom (resource specific) attributes. """direction=self.direction_key(direction)ifdirectionisNone:_log('Attempting to add evidence with non matching ''interaction partners.')returnevidence=(evidenceifisinstance(evidence,(pypath_evidence.Evidence,pypath_evidence.Evidences,))elsepypath_evidence.Evidence(resource=evidence,references=references,))ifhasattr(evidence,'update_attrs'):evidence.update_attrs(attrs)self.evidences+=evidenceself.direction[direction]+=evidenceifdirection!='undirected':ifeffectin{1,'positive','stimulation'}:self.positive[direction]+=evidenceelifeffectin{-1,'negative','inhibition'}:self.negative[direction]+=evidenceelifeffectin{0,'unknown'}:self.unknown_effect[direction]+=evidence
def__hash__(self):returnhash(self.key)def__eq__(self,other):returnhasattr(other,'key')andself.key==other.key@propertydef_key(self):returnInteractionKey(self.a.key,self.b.key,)def__iadd__(self,other):ifself!=other:_log('Attempt to merge interactions with ''non matching interaction partners.')returnselfself._merge_evidences(self,other)attrs_mod.AttributeHandler.__iadd__(self,other)returnselfdef__add__(self,other):new=self.__copy__()new+=otherreturnnewdef__copy__(self):new=Interaction(*self.key)new+=selfnew.update_attrs(self)returnnew@staticmethoddef_merge_evidences(one,other):one.evidences+=other.evidencesfordir_keyinone.direction.keys():one.direction[dir_key]+=other.direction[dir_key]foreff_keyinone.positive.keys():one.positive[eff_key]+=other.positive[eff_key]foreff_keyinone.negative.keys():one.negative[eff_key]+=other.negative[eff_key]foreff_keyinone.unknown_effect.keys():one.unknown_effect[eff_key]+=other.unknown_effect[eff_key]def__repr__(self):return'<Interaction: %s [%s]>'%(self.__str__(),self.evidences.__repr__().strip('<>'),)def__str__(self):return'%s%s=%s=%s=%s%s'%(self.a.labelorself.a.identifier,'<'ifself.direction[self.b_a]else'=',('(+-)'if(self.positive[self.b_a]andself.negative[self.b_a])else'(+)='ifself.positive[self.b_a]else'(-)='ifself.negative[self.b_a]else'===='),('(+-)'if(self.positive[self.a_b]andself.negative[self.a_b])else'(+)='ifself.positive[self.a_b]else'(-)='ifself.negative[self.a_b]else'===='),'>'ifself.direction[self.a_b]else'=',self.b.labelorself.b.identifier,)def__contains__(self,other):return(other==self.aorother==self.borself.evidences.__contains__(other)orattrs_mod.AttributeHandler.__contains__(self,other))defhas_data_model(self,data_model):returnself.evidences.has_data_model(data_model)@propertydefdata_models(self):return{ev.resource.data_modelforevinself.evidences}defhas_dataset(self,dataset:str,direction:str|tuple=None,effect:Literal['positive','negative']=None,**kwargs,)->bool:return(self.get_evidences(direction=direction,effect=effect).has_dataset(dataset,**kwargs))
[docs]defget_direction(self,direction,resources=False,evidences=False,sources=False,resource_names=False,):""" Returns the state (or *resources* if specified) of the given *direction*. :arg tuple direction: Or [str] (if ``'undirected'``). Pair of nodes from which direction information is to be retrieved. :arg bool resources: Optional, ``'False'`` by default. Specifies if the :py:attr:`resources` information of the given direction is to be retrieved instead. :return: (*bool* or *set*) -- (if ``resources=True``). Presence/absence of the requested direction (or the list of resources if specified). Returns ``None`` if *direction* is not valid. """direction=self.direction_key(direction)ifdirectionisnotNone:returnself._select_answer_type(self.direction[direction],resources=resources,evidences=evidences,resource_names=resource_names,sources=sources,)else:returnNone
[docs]defget_directions(self,src,tgt,resources=False,evidences=False,resource_names=False,sources=False,):""" Returns all directions with boolean values or list of sources. :arg str src: Source node. :arg str tgt: Target node. :arg bool resources: Optional, ``False`` by default. Specifies whether to return the :py:attr:`resources` attribute instead of :py:attr:`dirs`. :return: Contains the :py:attr:`dirs` (or :py:attr:`resources` if specified) of the given edge. """query=(src,tgt)answer_type_args={'resources':resources,'evidences':evidences,'resource_names':resource_names,'sources':sources,}query=self.direction_key(query)ifqueryisnotNone:return[self._select_answer_type(self.direction[query],**answer_type_args),self._select_answer_type(self.direction[tuple(reversed(query))],**answer_type_args),self._select_answer_type(self.direction['undirected'],**answer_type_args),]else:returnNone
[docs]defwhich_directions(self,resources=None,effect=None,):""" Returns the pair(s) of nodes for which there is information about their directionality. :arg str effect: Either *positive* or *negative*. :arg str,set resources: Limits the query to one or more resources. Optional. :return: (*tuple*) -- Tuple of tuples with pairs of nodes where the first element is the source and the second is the target entity, according to the given resources and limited to the effect. """resources=self._resources_set(resources)effect=self._effect_synonyms(effect)returntuple(_dirfor_dir,_evidencesiniteritems(self.direction)if_dir!='undirected'and_evidencesand(notresourcesor_evidences&resources)and(noteffector(notresourcesandgetattr(self,effect)[_dir])orgetattr(self,effect)[_dir]&resources))
# synonym: old namewhich_dirs=which_directions
[docs]defwhich_signs(self,resources=None,effect=None):""" Returns the pair(s) of nodes for which there is information about their effect signs. :param str,set resources: Limits the query to one or more resources. Optional. :param str effect: Either *positive* or *negative*, limiting the query to positive or negative effects; for any other values effects of both signs will be returned. :return: (*tuple*) -- Tuple of tuples with pairs of nodes where the first element is a tuple of the source and the target entity, while the second element is the effect sign, according to the given resources. E.g. ((('A', 'B'), 'positive'),) """resources=self._resources_set(resources)effect=self._effect_synonyms(effect)effects=(effect,)ifeffectelse('positive','negative')returntuple((_dir,_effect)for_effectineffectsfor_dir,_evidencesiniteritems(getattr(self,_effect))if_evidencesand(notresourcesor_evidences&resources))
[docs]defunset_direction(self,direction,only_sign=False,resource=None,interaction_type=None,via=False,source=None,):""" Removes directionality and/or source information of the specified *direction*. Modifies attribute :py:attr:`dirs` and :py:attr:`sources`. :arg tuple direction: Or [str] (if ``'undirected'``) the pair of nodes specifying the directionality from which the information is to be removed. :arg set resource: Optional, ``None`` by default. If specified, determines which specific source(s) is(are) to be removed from :py:attr:`sources` attribute in the specified *direction*. """direction=self.direction_key(direction)ifdirectionisnotNone:attrs=((self._effect_synonyms(only_sign),)ifonly_signelse('direction','positive','negative','unknown_effect'))resource=resourceorsourceforattrinattrs:ifresourceisnotNone:getattr(self,attr)[direction].remove(resource=resource,interaction_type=interaction_type,via=via,)else:getattr(self,attr)[direction]=(pypath_evidence.Evidences())
# synonym: old nameunset_dir=unset_direction
[docs]defunset_sign(self,direction,sign,resource=None,interaction_type=None,via=False,source=None,):""" Removes sign and/or source information of the specified *direction* and *sign*. Modifies attribute :py:attr:`positive` and :py:attr:`positive_sources` or :py:attr:`negative` and :py:attr:`negative_sources` (or :py:attr:`positive_attributes`/:py:attr:`negative_sources` only if ``source=True``). :arg tuple direction: The pair of nodes specifying the directionality from which the information is to be removed. :arg str sign: Sign from which the information is to be removed. Must be either ``'positive'`` or ``'negative'``. :arg set source: Optional, ``None`` by default. If specified, determines which source(s) is(are) to be removed from the sources in the specified *direction* and *sign*. """self.unset_direction(direction=direction,only_sign=sign,resource=resource,interaction_type=interaction_type,via=via,source=source,)
[docs]defunset_interaction_type(self,interaction_type):""" Removes all evidences with a certain ``interaction_type``. """forevintuple(self.evidences):ifev.resource.interaction_type==interaction_type:self.evidences-=evforattrin('direction','positive','negative'):forkey,evsingetattr(self,attr):forevintuple(evs):ifev.resource.interaction_type==interaction_type:evs-=ev
[docs]defis_directed(self):""" Checks if edge has any directionality information. :return: (*bool*) -- Returns ``True`` if any of the :py:attr:`dirs` attribute values is ``True`` (except ``'undirected'``), ``False`` otherwise. """returnany(evsfordkey,evsiniteritems(self.direction)ifdkey!='undirected')
[docs]defis_directed_by_resources(self,resources=None):""" Checks if edge has any directionality information from some resource(s). :return: (*bool*) -- Returns ``True`` if any of the :py:attr:`dirs` attribute values is ``True`` (except ``'undirected'``), ``False`` otherwise. """returnself._dir_by_resource(resources,op=operator.or_)
defis_mutual(self,resources=None):""" Checks if the edge has mutual directions (both A-->B and B-->A). """return(bool(self.direction[self.a_b])andbool(self.direction[self.b_a])ifnotresourceselseself.is_mutual_by_resources(resources=resources))
[docs]defis_mutual_by_resources(self,resources=None):""" Checks if the edge has mutual directions (both A-->B and B-->A) according to some resource(s). """returnself._dir_by_resource(resources,op=operator.and_)
[docs]defis_loop(self):""" :returns: ``True`` if the interaction is a loop edge i.e. its endpoints are the same node. """returnself.a==self.b
[docs]defis_stimulation(self,direction=None,resources=None):""" Checks if any (or for a specific *direction*) interaction is activation (positive interaction). :arg tuple direction: Optional, ``None`` by default. If specified, checks the :py:attr:`positive` attribute of that specific directionality. If not specified, checks both. :return: (*bool*) -- ``True`` if any interaction (or the specified *direction*) is activatory (positive). """returnself._is_effect(sign='positive',direction=direction,resources=resources,)
[docs]defis_inhibition(self,direction=None,resources=None):""" Checks if any (or for a specific *direction*) interaction is inhibition (negative interaction). :arg tuple direction: Optional, ``None`` by default. If specified, checks the :py:attr:`negative` attribute of that specific directionality. If not specified, checks both. :return: (*bool*) -- ``True`` if any interaction (or the specified *direction*) is inhibitory (negative). """returnself._is_effect(sign='negative',direction=direction,resources=resources,)
[docs]defhas_sign(self,direction=None,resources=None):""" Checks whether the edge (or for a specific *direction*) has any signed information (about positive/negative interactions). :arg tuple direction: Optional, ``None`` by default. If specified, only the information of that direction is checked for sign. :return: (*bool*) -- ``True`` if there exist any information on the sign of the interaction, ``False`` otherwise. """return(self.is_stimulation(direction=direction,resources=resources)orself.is_inhibition(direction=direction,resources=resources))
[docs]defadd_sign(self,direction:tuple,sign:str,resource:str|set[str]|None=None,resource_name:str=None,interaction_type:str='PPI',data_model:str=None,attrs:dict=None,**kwargs):""" Sets sign and source information on a given direction of the edge. Modifies the attributes :py:attr:`positive` and :py:attr:`positive_sources` or :py:attr:`negative` and :py:attr:`negative_sources` depending on the sign. Direction is also updated accordingly, which also modifies the attributes :py:attr:`dirs` and :py:attr:`sources`. Args direction: Pair of edge nodes specifying the direction from which the information is to be set/updated. sign: Specifies the type of interaction. Either ``'positive'`` or ``'negative'``. resource: Contains the name(s) of the source(s) from which the information was obtained. attrs: Custom (resource specific) edge attributes. kwargs: Passed to ``pypath.resource.NetworkResource`` if ``resource`` is not already a ``NetworkResource`` or ``Evidence`` instance. """sign=self._effect_synonyms(sign)evidence=(resourceifisinstance(resource,pypath_evidence.Evidence)elsepypath_evidence.Evidence(resource=resource,references=references,)ifisinstance(resource,pypath_resource.NetworkResource)elsepypath_evidence.Evidence(resource=pypath_resource.NetworkResource(name=resource_name,interaction_type=interaction_type,data_model=data_model,**kwargs))ifresource_nameisnotNoneelseNone)evidence.update_attrs(attrs)direction=self.direction_key(direction)ifself._directed_key(direction)andevidenceisnotNone:ev_attr=getattr(self,sign)ev_attr+=evidence
[docs]defget_sign(self,direction:tuple,sign:str=None,evidences:bool=False,resources:bool=False,resource_names:bool=False,sources:bool=False,)->list[bool|str]:""" Retrieves the sign information of the edge in the given diretion. If specified in *sign*, only that sign's information will be retrieved. If specified in *sources*, the sources of that information will be retrieved instead. Args direction: Contains the pair of nodes specifying the directionality of the edge from which th information is to be retrieved. sign: Optional, ``None`` by default. Denotes whether to retrieve the ``'positive'`` or ``'negative'`` specific information. resources: Optional, ``False`` by default. Specifies whether to return the resources instead of sign. Returns If ``sign=None`` containing [bool] values denoting the presence of positive and negative sign on that direction, if ``sources=True`` the [set] of sources for each of them will be returned instead. If *sign* is specified, returns [bool] or [set] (if ``sources=True``) of that specific direction and sign. """sign=self._effect_synonyms(sign)answer_type_args={'resources':resources,'evidences':evidences,'resource_names':resource_names,'sources':sources,}direction=self.direction_key(direction)ifself._directed_key(direction):return(self._select_answer_type(getattr(self,sign)[direction],**answer_type_args)ifsignelse[self._select_answer_type(self.positive[direction],**answer_type_args),self._select_answer_type(self.negative[direction],**answer_type_args)])
[docs]defsource(self,undirected:bool=False,resources=None,**kwargs):""" Returns the name(s) of the source node(s) for each existing direction on the interaction. Args undirected: Optional, ``False`` by default. Returns (*list*) -- Contains the name(s) for the source node(s). This means if the interaction is bidirectional, the list will contain both identifiers on the edge. If the interaction is undirected, an empty list will be returned. """returnself._partner(source_target='source',undirected=undirected,resources=resources,**kwargs)
# synonym: old namesrc=source
[docs]deftarget(self,undirected:bool=False,resources=None,**kwargs):""" Returns the name(s) of the target node(s) for each existing direction on the interaction. Args undirected: Optional, ``False`` by default. Returns (*list*) -- Contains the name(s) for the target node(s). This means if the interaction is bidirectional, the list will contain both identifiers on the edge. If the interaction is undirected, an empty list will be returned. """returnself._partner(source_target='target',undirected=undirected,resources=resources,**kwargs)
# synonym: old nametgt=targetdef_partner(self,source_target,undirected=False,resources=None,**kwargs):resources=self._resources_set(resources)_slice=slice(0,1)ifsource_target=='source'elseslice(1,2)returntuple(itertools.chain((_direction[_slice]if_direction!='undirected'elseself.nodesifundirectedelse())for_direction,_evidencesiniteritems(self.direction)if(((notresourcesandnotkwargsandbool(_evidences))or(any(ev.match(resource=res,**kwargs)forresinresourcesor(None,)forevin_evidences))))))
[docs]defsrc_by_resource(self,resource):""" Returns the name(s) of the source node(s) for each existing direction on the interaction for a specific *resource*. :arg str resource: Name of the resource according to which the information is to be retrieved. :return: (*list*) -- Contains the name(s) for the source node(s) according to the specified *resource*. This means if the interaction is bidirectional, the list will contain both identifiers on the edge. If the specified *source* is not found or invalid, an empty list will be returned. """return[_dir[0]for_dir,_evidencesiniteritems(self.direction)if(_dir!='undirected'andresourcein_evidences)]
[docs]deftgt_by_resource(self,resource):""" Returns the name(s) of the target node(s) for each existing direction on the interaction for a specific *resource*. :arg str resource: Name of the resource according to which the information is to be retrieved. :return: (*list*) -- Contains the name(s) for the target node(s) according to the specified *resource*. This means if the interaction is bidirectional, the list will contain both identifiers on the edge. If the specified *source* is not found or invalid, an empty list will be returned. """return[_dir[1]for_dir,_evidencesiniteritems(self.direction)if(_dir!='undirected'andresourcein_evidences)]
[docs]defresources_a_b(self,resources=False,evidences=False,resource_names=False,sources=False,):""" Retrieves the list of resources for the :py:attr:`a_b` direction. :return: (*set*) -- Contains the names of the sources supporting the :py:attr:`a_b` directionality of the edge. """answer_type_args={'resources':resources,'evidences':evidences,'resource_names':resource_names,'sources':sources,}returnself._select_answer_type(self.direction[self.a_b],**answer_type_args)
# synonym for old method namesources_straight=resources_a_b
[docs]defresources_b_a(self,resources=False,evidences=False,resource_names=False,sources=False,):""" Retrieves the list of sources for the :py:attr:`b_a` direction. :return: (*set*) -- Contains the names of the sources supporting the :py:attr:`b_a` directionality of the edge. """answer_type_args={'resources':resources,'evidences':evidences,'resource_names':resource_names,'sources':sources,}returnself._select_answer_type(self.direction[self.b_a],**answer_type_args)
# synonym for old method namesources_reverse=resources_b_a
[docs]defresources_undirected(self,resources=False,evidences=False,resource_names=False,sources=False,):""" Retrieves the list of resources without directed information. :return: (*set*) -- Contains the names of the sources supporting the edge presence but without specific directionality information. """answer_type_args={'resources':resources,'evidences':evidences,'resource_names':resource_names,'sources':sources,}returnself._select_answer_type(self.direction['undirected'],**answer_type_args)
sources_undirected=resources_undirected
[docs]defpositive_a_b(self):""" Checks if the :py:attr:`a_b` directionality is a positive interaction. :return: (*bool*) -- ``True`` if there is supporting information on the :py:attr:`a_b` direction of the edge as activation. ``False`` otherwise. """returnbool(self.positive[self.a_b])
positive_straight=positive_a_b
[docs]defpositive_b_a(self):""" Checks if the :py:attr:`b_a` directionality is a positive interaction. :return: (*bool*) -- ``True`` if there is supporting information on the :py:attr:`b_a` direction of the edge as activation. ``False`` otherwise. """returnbool(self.positive[self.b_a])
positive_reverse=positive_b_a
[docs]defnegative_a_b(self):""" Checks if the :py:attr:`a_b` directionality is a negative interaction. :return: (*bool*) -- ``True`` if there is supporting information on the :py:attr:`a_b` direction of the edge as inhibition. ``False`` otherwise. """returnbool(self.negative[self.a_b])
negative_straight=negative_a_b
[docs]defnegative_b_a(self):""" Checks if the :py:attr:`b_a` directionality is a negative interaction. :return: (*bool*) -- ``True`` if there is supporting information on the :py:attr:`b_a` direction of the edge as inhibition. ``False`` otherwise. """returnbool(self.negative[self.b_a])
negative_reverse=negative_b_a
[docs]defnegative_resources_a_b(self,**kwargs):""" Retrieves the list of resources for the :py:attr:`a_b` direction and negative sign. :return: (*set*) -- Contains the names of the resources supporting the :py:attr:`a_b` directionality of the edge with a negative sign. """answer_type_args={'resource_names':True}answer_type_args.update(kwargs)returnself._select_answer_type(self.negative[self.a_b],**answer_type_args)
[docs]defnegative_resources_b_a(self,**kwargs):""" Retrieves the list of resources for the :py:attr:`b_a` direction and negative sign. :return: (*set*) -- Contains the names of the resources supporting the :py:attr:`b_a` directionality of the edge with a negative sign. """answer_type_args={'resource_names':True}answer_type_args.update(kwargs)returnself._select_answer_type(self.negative[self.b_a],**answer_type_args)
[docs]defpositive_resources_a_b(self,**kwargs):""" Retrieves the list of resources for the :py:attr:`a_b` direction and positive sign. :return: (*set*) -- Contains the names of the resources supporting the :py:attr:`a_b` directionality of the edge with a positive sign. """answer_type_args={'resource_names':True}answer_type_args.update(kwargs)returnself._select_answer_type(self.positive[self.a_b],**answer_type_args)
[docs]defpositive_resources_b_a(self,**kwargs):""" Retrieves the list of resources for the :py:attr:`b_a` direction and positive sign. :return: (*set*) -- Contains the names of the resources supporting the :py:attr:`b_a` directionality of the edge with a positive sign. """answer_type_args={'resource_names':True}answer_type_args.update(kwargs)returnself._select_answer_type(self.positive[self.b_a],**answer_type_args)
[docs]defmajority_dir(self,only_interaction_type=None,only_primary=True,by_references=False,by_reference_resource_pairs=True,):""" Infers which is the major directionality of the edge by number of supporting sources. :return: (*tuple*) -- Contains the pair of nodes denoting the consensus directionality. If the number of sources on both directions is equal, ``None`` is returned. If there is no directionality information, ``'undirected'``` will be returned. """a_b=self.direction[self.a_b]b_a=self.direction[self.b_a]ifnota_bandnotb_a:return'undirected'method=('count_references'ifby_referenceselse'count_curation_effort'ifby_reference_resource_pairselse'count_resources')n_a_b=getattr(a_b,method)(interaction_type=only_interaction_type,via=Falseifonly_primaryelseNone,)n_b_a=getattr(b_a,method)(interaction_type=only_interaction_type,via=Falseifonly_primaryelseNone,)return('undirected'ifn_a_b==0andn_b_a==0elseNoneifn_a_b==n_b_aelseself.a_bifn_a_b>n_b_aelseself.b_a)
[docs]defmajority_sign(self,only_interaction_type=None,only_primary=True,by_references=False,by_reference_resource_pairs=True,):""" Infers which is the major sign (activation/inhibition) of the edge by number of supporting sources on both directions. :return: (*dict*) -- Keys are the node tuples on both directions (:py:attr:`straight`/:py:attr:`reverse`) and values can be either ``None`` if that direction has no sign information or a list of two [bool] elements corresponding to majority of positive and majority of negative support. In case both elements of the list are ``True``, this means the number of supporting sources for both signs in that direction is equal. """result={}method=('count_references'ifby_referenceselse'count_curation_effort'ifby_reference_resource_pairselse'count_resources')for_dirin(self.a_b,self.b_a):n_pos=getattr(self.positive[_dir],method)(interaction_type=only_interaction_type,via=Falseifonly_primaryelseNone,)n_neg=getattr(self.negative[_dir],method)(interaction_type=only_interaction_type,via=Falseifonly_primaryelseNone,)result[_dir]=[0<n_pos>=n_neg,0<n_neg>=n_pos,]returnresult
[docs]defconsensus(self,only_interaction_type=None,only_primary=False,by_references=False,by_reference_resource_pairs=True,):""" Infers the consensus edge(s) according to the number of supporting sources. This includes direction and sign. :return: (*list*) -- Contains the consensus edge(s) along with the consensus sign. If there is no major directionality, both are returned. The structure is as follows: ``['<source>', '<target>', '<(un)directed>', '<sign>']`` """result=[]_dir=self.majority_dir(only_interaction_type=only_interaction_type,only_primary=only_primary,by_references=by_references,by_reference_resource_pairs=by_reference_resource_pairs,)if_dir=='undirected'or_dirisNone:_dir=self.majority_dir(only_interaction_type=only_interaction_type,only_primary=only_primary,by_references=False,by_reference_resource_pairs=False,)_effect=self.majority_sign(only_interaction_type=only_interaction_type,only_primary=only_primary,by_references=by_references,by_reference_resource_pairs=by_reference_resource_pairs,)_effect_noref=self.majority_sign(only_interaction_type=only_interaction_type,only_primary=only_primary,by_references=False,by_reference_resource_pairs=False,)if_dir=='undirected':result.append([self.a_b[0],self.a_b[1],'undirected','unknown',])else:dirs=(self.a_b,self.b_a)if_dirisNoneelse(_dir,)fordindirs:d_effect=(_effect[d]if(_effect[d]isnotNoneand_effect[d][0]!=_effect[d][1])else_effect_noref[d])ifd_effectisnotNone:# index #0 is positiveifd_effect[0]:result.append([d[0],d[1],'directed','positive',])# can not be elif bc of the case of equal weight of# evidences for both positive and negativeifd_effect[1]:result.append([d[0],d[1],'directed','negative',])# directed with unknown effectelse:result.append([d[0],d[1],'directed','unknown',])returnresult
consensus_edges=consensus
[docs]defmerge(self,other):""" Merges current Interaction with another (if and only if they are the same class and contain the same nodes). Updates the attributes :py:attr:`direction`, :py:attr:`positive` and :py:attr:`negative`. :arg pypath.interaction.Interaction other: The new Interaction object to be merged with the current one. """ifnotself._check_nodes_key(other.nodes):_log('Attempting to merge Interaction instances with different ''interacting partners.')returnself.evidences+=other.evidencesforattr,_dirinitertools.product(('direction','positive','negative'),(self.a_b,self.b_a,'undirected')):ifattr!='direction'and_dir=='undirected':continuegetattr(self,attr)[_dir]+=getattr(other,attr)[_dir]
[docs]deftranslate(self,ids,new_attrs=None):""" Translates the node names/identifiers according to the dictionary *ids*. Also is able to change attributes like `id_type`, `taxon` and `entity_type`. :arg dict ids: Dictionary containing (at least) the current names of the nodes as keys and their translation as values. :arg dict new_attrs: Dictionary with new IDs as keys and their dicts of their new attributes as values. For any attribute not provided here the attributes from the original instance will be used. E.g. you can provide `{'1956': {'id_type': 'entrez'}}' if the new ID type for protein EGFR is Entrez Gene ID. :return: (*pypath.main.Direction*) -- The copy of current edge object with translated node names. """new_a=ids[self.nodes[0]]new_b=ids[self.nodes[1]]new_ids={'a':new_a,'b':new_b}to_old=common.swap_dict_simple(ids)all_new_attrs=dict(('%s_%s'%(attr,label),new_attrs[new_ids[label]][attr]if(new_ids[label]innew_attrsandattrinnew_attrs[new_ids[label]])elsegetattr(getattr(self,label),attr))forattrin('id_type','entity_type','taxon')forlabelin('a','b'))all_new_attrs['attrs']=new_attrs.get('attrs',self.attrs)new=Interaction(a=new_a,b=new_b,**all_new_attrs)new.evidences+=self.evidencesto_old=dict((new_id,self.id_to_entity(old_id))fornew_id,old_idiniteritems(to_old))# this is required to handle also loop edgesnew_old_a_b=((to_old[new.a.identifier],to_old[new.b.identifier],)ifnew.a!=new.belseself.a_b)new_old_b_a=((to_old[new.b.identifier],to_old[new.a.identifier],)ifnew.a!=new.belseself.b_a)for(old_dir,new_dir),attrinitertools.product(zip((new_old_a_b,new_old_b_a,'undirected'),(new.a_b,new.b_a,'undirected',),),('direction','positive','negative'),):ifold_dir=='undirected'andattr!='direction':continuegetattr(new,attr)[new_dir]+=getattr(self,attr)[old_dir]returnnew
deforthology_translate_one(self,id_a,id_b,taxon):returnself.translate(ids={self.a:id_a,self.b:id_b,},new_attrs={id_a:{'taxon':(self.a.taxonifid_a==self.a.identifierelsetaxon),},id_b:{'taxon':(self.b.taxonifid_b==self.b.identifierelsetaxon),},},)deforthology_translate(self,taxon,exclude=None):exclude=excludeorset()exclude.add(0)fornew_a,new_binitertools.product((self.a.identifier,)ifself.a.taxoninexcludeelseorthology.translate(source_id=self.a.identifier,target=taxon,source=self.a.taxon,),(self.b.identifier,)ifself.b.taxoninexcludeelseorthology.translate(source_id=self.b.identifier,target=taxon,source=self.b.taxon,),):yieldself.orthology_translate_one(id_a=new_a,id_b=new_b,taxon=taxon,)defget_evidences(self,direction=None,effect=None,resources=None,data_model=None,interaction_type=None,via=None,references=None,datasets=None,):effect=self._effect_synonyms(effect)evidences=(# any signedsum(itertools.chain(self.positive.values(),self.negative.values(),))ifeffect==Trueelse# only positive(self.positive[direction]ifdirectioninself.positiveelsesum(self.positive.values()))ifeffect=='positive'else# only negative(self.negative[direction]ifdirectioninself.negativeelsesum(self.negative.values()))ifeffect=='negative'else# any directedsum(self.direction[_dir]for_dirinself.which_dirs())ifdirection==Trueelse# one specific directionself.direction[direction]ifdirectioninself.directionelse# all evidences (default)self.evidences)return(pypath_evidence.Evidences(evidences.filter(resource=resources,interaction_type=interaction_type,via=via,data_model=data_model,references=references,datasets=datasets,)))
[docs]defget_entities(self,entity_type=None,direction=None,effect=None,resources=None,data_model=None,interaction_type=None,via=None,references=None,datasets=None,return_type=None,):""" Retrieves the entities involved in interactions matching the criteria. It either returns both interacting entities in a *set* or an empty *set*. This may not sound so useful at the level of this object but becomes more useful once we want to collect entities having certain kind of interactions across a series of `Interaction` objects. :arg str entity_type: The type of the molecular entity. Possible values: `protein`, `complex`, `mirna`, `small_molecule`. :arg str return_type: The type of values to return. Default is py:class:``pypath.entity.Entity`` objects, alternatives are ``labels`` ``identifiers``. """# TODO: this method could be made slightly more efficient by using# not ``get_interactions`` but a simpler logic as here we don't need# to handle the directions separately; however this is not very# important and for the time being it's good as it is.kwargs=locals()_=kwargs.pop('self')entity_type=common.to_set(kwargs.pop('entity_type'))return_type=kwargs.pop('return_type')return_types={'entity':None,'entities':None,'id':'identifier','name':'identifier',}# allow pluralsreturn_type=(return_type[:-1]if(isinstance(return_type,str)andreturn_type[-1]=='s')elsereturn_type)# allow some synonymsreturn_type=(return_types[return_type]ifreturn_typeinreturn_typeselsereturn_type)return(set((getattr(en,return_type)ifreturn_typeandhasattr(en,return_type)elseen)foreninitertools.chain(*self.get_interactions(**kwargs))ifnotentity_typeoren.entity_typeinentity_type))
[docs]defget_interactions(self,direction=None,effect=None,resources=None,data_model=None,interaction_type=None,via=None,references=None,entity_type=None,source_entity_type=None,target_entity_type=None,datasets=None,):""" Returns one or two tuples of the interacting partners: one if only one direction, two if both directions match the query criteria. The tuple will be empty if no evidence matches the criteria. :arg NontType,bool,tuple direction: If `None` both undirected and directed, if `True` only directed, if a *tuple* of entities only the interactions with that specific direction will be considered. Unless you set this parameter to `True` this method will return both directions if one or more undirected resources present. If `False`, only the undirected interactions will be considered, and if any resource annotates this interaction as undirected both directions will be returned. However the ``count_interactions_undirected`` method will return `1` in this case. :arg NoneType,bool,str effect: If `None` also interactions without effect, if `True` only the ones with any effect, if a string naming an effect only the interactions with that specific effect will be considered. :arg NontType,str,set resources: Optionally limit the query to one or more resources. :arg NontType,str,set data_model: Optionally limit the query to one or more data models e.g. `activity_flow`. :arg NontType,str,set interaction_type: Optionally limit the query to one or more interaction types e.g. `PPI`. :arg NontType,bool,str,set via: Optionally limit the query to certain secondary databases or if `False` consider only data from primary databases. :arg str entity_type: Molecule type for both of the entities. :arg str source_entity_type: Molecule type for the source entity. :arg str target_entity_type: Molecule type for the target entity. """effect=self._effect_synonyms(effect)direction=(self.direction_key(direction)ifisinstance(direction,tuple)elsedirection)entity_type=common.to_set(entity_type)source_entity_type=common.to_set(source_entity_type)orentity_typetarget_entity_type=common.to_set(target_entity_type)orentity_typereturntuple(# direction key_dir# possible directionsfor_dirin(self.a_b,self.b_a)# conditions by selecting and evaluating evidence collectionsif((notsource_entity_typeor_dir[0].entity_typeinsource_entity_type)and(nottarget_entity_typeor_dir[1].entity_typeintarget_entity_type))and(self.evaluate_evidences(this_direction=_dir,direction=direction,effect=effect,resources=resources,data_model=data_model,interaction_type=interaction_type,via=via,references=references,datasets=datasets,)))
[docs]defevaluate_evidences(self,this_direction,direction=None,effect=None,resources=None,data_model=None,interaction_type=None,via=None,references=None,datasets=None,):""" Selects the evidence collections matching the direction and effect criteria and then evaluates if any of the evidences in these collections match the evidence criteria. """kwargs=locals()_=kwargs.pop('self')returnany(self.iter_match_evidences(**kwargs))
[docs]defiter_match_evidences(self,this_direction,direction=None,effect=None,resources=None,data_model=None,interaction_type=None,via=None,references=None,datasets=None,):""" Selects the evidence collections matching the direction and effect criteria and yields collections matching the evidence criteria. """forevsinself.iter_evidences(this_direction=this_direction,direction=direction,effect=effect,):ifevs.match(resource=resources,data_model=data_model,interaction_type=interaction_type,via=via,references=references,datasets=datasets,):yieldevs
[docs]defiter_evidences(self,this_direction,direction=None,effect=None,):""" Selects and yields evidence collections matching the direction and effect criteria. """# evidence keysforevs_keyin('undirected',this_direction):# evidence dictsforthis_effectin('direction','positive','negative'):if(# only undirected(direction==Falseandevs_key=='undirected'andthis_effect=='direction')or# undirected(directionisNoneandnoteffectandthis_effect=='direction')or# directed(direction!=Falseandevs_key!='undirected'andthis_effect=='direction'andnoteffectand(# any directiondirection==Trueor# specific directiondirection==this_direction))or# with effect(direction!=Falseandevs_key!='undirected'andthis_effect!='direction'and(# any effecteffect==Trueor# specific effecteffect==this_effect))):# getting the evidence dict and the key from ityieldgetattr(self,this_effect)[evs_key]
[docs]defget_interactions_0(self,**kwargs):""" Returns unique interacting pairs without being aware of the direction. """kwargs['direction']=Nonekwargs['effect']=Noneresult=self.get_interactions(**kwargs)returnresult[:1]ifresultelse()
[docs]defget_interactions_directed(self,**kwargs):""" Args kwargs: See the docs of method ``get_interactions``. """if'direction'notinkwargsorkwargs['direction']isNone:kwargs['direction']=Truereturnself.get_interactions(**kwargs)
[docs]defget_interactions_undirected(self,**kwargs):""" Only the undirected interactions will be considered, if any resource annotates this interaction as undirected both directions will be returned, no matter if certain resources provide direction. However the ``count_interactions_undirected`` method will return `1` in this case. Args kwargs: See the docs of method ``get_interactions``. """kwargs['direction']=Falsereturnself.get_interactions(**kwargs)
[docs]defget_interactions_undirected_0(self,**kwargs):""" Only the undirected interactions will be considered, if any resource annotates this interaction as undirected the interacting pair as a sorted tuple will be returned inside a one element tuple. Args kwargs: See the docs of method ``get_interactions``. """undir=self.get_interactions_undirected(**kwargs)returnundir[:1]ifundirelse()
[docs]defget_interactions_non_directed(self,**kwargs):""" Only the undirected interactions will be considered, if any resource annotates this interaction as undirected both directions will be returned, but only if no resource provide direction. However the ``count_interactions_non_directed`` method will return `1` in this case. Args kwargs: See the docs of method ``get_interactions``. """kwargs['direction']=Truereturn(self.get_interactions_undirected(**kwargs)ifnotself.get_interactions(**kwargs)else())
[docs]defget_interactions_non_directed_0(self,**kwargs):""" Only the undirected interactions will be considered, if any resource annotates this interaction as undirected and none as directed, the interacting pair as a sorted tuple will be returned inside a one element tuple. Args kwargs: See the docs of method ``get_interactions``. """nondir=self.get_interactions_non_directed(**kwargs)returnnondir[:1]ifnondirelse()
[docs]defget_interactions_signed(self,**kwargs):""" Args kwargs: See the docs of method ``get_interactions``. """if'effect'notinkwargsorkwargs['effect']isNone:kwargs['effect']=Truereturnself.get_interactions(**kwargs)
[docs]defget_interactions_positive(self,**kwargs):""" Args kwargs: See the docs of method ``get_interactions``. """kwargs['effect']='positive'returnself.get_interactions(**kwargs)
[docs]defget_interactions_negative(self,**kwargs):""" Args kwargs: See the docs of method ``get_interactions``. """kwargs['effect']='negative'returnself.get_interactions(**kwargs)
[docs]defget_interactions_mutual(self,**kwargs):""" Note: undirected interactions does not count as mutual but only interactions with explicit direction information for both directions. Args kwargs: See the docs of method ``get_interactions``. """if'direction'notinkwargsorkwargs['direction']isNone:kwargs['direction']=Trueinteractions=self.get_interactions(**kwargs)returninteractionsiflen(interactions)==2else()
[docs]defis_mutual(self,**kwargs):""" Note: undirected interactions does not count as mutual but only interactions with explicit direction information for both directions. Args kwargs: See the docs of method ``get_interactions``. """returnbool(self.get_interactions_mutual(**kwargs))
[docs]defcount_interactions_mutual(self,**kwargs):""" Note: undirected interactions does not count as mutual but only interactions with explicit direction information for both directions. Args kwargs: See the docs of method ``get_interactions``. """returnint(self.is_mutual(**kwargs))
[docs]defcount_interactions_undirected(self,**kwargs):""" Returns `True` if any resource annotates this interaction without direction. Args kwargs: See the docs of method ``get_interactions``. """returnbool(self.get_interactions_undirected(**kwargs))
[docs]defcount_interactions_non_directed(self,**kwargs):""" Returns `True` if any resource annotates this interaction without and no resource with direction. Args kwargs: See the docs of method ``get_interactions``. """returnbool(self.get_interactions_non_directed(**kwargs))
[docs]defget_degrees(self,mode:str,direction=None,effect=None,resources=None,data_model=None,interaction_type=None,via=None,references=None,):""" Returns a *set* of nodes with the connections matching the direction, effect and evidence criteria. E.g. if the query concerns the incoming degrees with positive effect and the matching evidences show A activates B, but not the other way around, only "B" will be returned. Args mode: The type of degrees to be considered. Three possible values are ``'IN'``, `'OUT'`` and ``'ALL'`` for incoming, outgoing and all connections, respectively. If the ``direction`` is ``False`` the only possible mode is ``ALL``. If the ``direction`` is ``None`` and also directed evidence(s) match the criteria these will overwrite the undirected evidences and only the directed result will be returned. """kwargs=locals()_=kwargs.pop('self')mode=kwargs.pop('mode')idx={'ALL':(0,2),'OUT':(0,1),'IN':(1,2),}ifdirection==False:mode='ALL'ifdirectionisNoneandnoteffect:_=kwargs.pop('direction')return(self.get_degrees(mode=mode,direction=True,**kwargs)orself.get_degrees(mode=mode,direction=False,**kwargs))result=set()node_pairs=self.get_interactions(**kwargs)forpairinnode_pairs:result.update(pair[idx[mode][0]:idx[mode][1]])returnresult
defget_curation_effort(self,**kwargs):returntuple((self.a,self.b,res,ref)forres,refsiniteritems(self.references_by_resource(**kwargs))forrefinrefs)@staticmethoddef_get(self,method,**kwargs):via=kwargs['via']if'via'inkwargselseFalsereturngetattr(self.get_evidences(**kwargs),'get_%s'%method,)(via=via)@staticmethoddef_count(method):@functools.wraps(method)defcount_method(*args,**kwargs):returnlen(method(*args,**kwargs))returncount_method@staticmethoddef_by(method,by='resources'):by=(by,)ifisinstance(by,str)elseby@functools.wraps(method)defby_method(*args,**kwargs):self=args[0]name_keys=kwargs.pop('name_keys',True)for_byinby:_=kwargs.pop(_by,None)levels_methods=('get_%s%ss'%(_by[:-1]if_byin{'resources','references'}else_by,'_name'if_by=='resources'andname_keyselse'')for_byinby)levels=list(itertools.product(*(getattr(self,levels_method)(**kwargs)forlevels_methodinlevels_methods)))result=dict((_levelsiflen(_levels)>1else_levels[0],method(*args,**dict(zip(by,_levels)),**kwargs))for_levelsinlevels)returndict((k,v)fork,viniteritems(result)ifv)returnby_method@classmethoddef_by_resource(cls,method):returncls._by(method,by='resources')@classmethoddef_by_data_model(cls,method):returncls._by(method,by='data_model')@classmethoddef_by_interaction_type_and_data_model(cls,method):returncls._by(method,by=('interaction_type','data_model'))@classmethoddef_by_interaction_type_and_data_model_and_resource(cls,method):returncls._by(method,by=('interaction_type','data_model','resources'),)@classmethoddef_by_interaction_type(cls,method):returncls._by(method,by='interaction_type')@classmethoddef_by_reference(cls,method):returncls._by(method,by='references')@classmethoddef_generate_get_methods(cls):def_create_get_method(method):@functools.wraps(method)def_get_method(*args,**kwargs):returncls._get(self=args[0],method=method,**kwargs)return_get_methodfor_getincls._get_methods_autogen:method_name='get_%s'%_getsignature=cls._update_get_method_signature(method_name)cls._add_method(method_name=method_name,method=_create_get_method(_get),# this is not always correct, to be fixed latersignature=signature,doc=('Retrieves %s matching the criteria.'%(_get.replace('_',' '))),)@classmethoddef_generate_degree_methods(cls):def_create_degree_method(mode,direction,effect):wrap_args=mode,direction,effect@functools.wraps(wrap_args)def_degree_method(*args,**kwargs):mode,direction,effect=wrap_argskwargs['direction']=directionkwargs['effect']=effectreturncls.get_degrees(self=args[0],mode=mode,**kwargs)return_degree_methodformode,(dir_label,dir_args)initertools.product(cls._degree_modes,iteritems(cls._degree_directions)):ifdir_labelin{'undirected','non_directed'}andmode!='ALL':continuemethod_name='degrees_%s%s'%(dir_label,'_%s'%mode.lower()ifmode!='ALL'else'')cls._count_methods.add(method_name)cls._get_methods.add(method_name)method=_create_degree_method(mode,*dir_args)_method_name='get_%s'%method_namecls._add_method(method_name=_method_name,method=method,signature=['mode']+cls._get_method_signature,doc=cls.get_degrees.__doc__,)@classmethoddef_generate_count_methods(cls):for_getincls._count_methods:_get_method=getattr(cls,'get_%s'%_get)method_name='count_%s'%_getsignature=cls._update_get_method_signature(method_name)cls._add_method(method_name=method_name,method=cls._count(_get_method),signature=cls._get_method_signature,doc=_get_method.__doc__,)@classmethoddef_update_get_method_signature(cls,method_name):signature=cls._get_method_signatureif'interaction'inmethod_name:signature=signature+[('entity_type',None),('source_entity_type',None),('target_entity_type',None),]returnsignature@classmethoddef_generate_by_methods(cls):for_get,_byinitertools.product(cls._get_methods,cls._by_methods,):_get_method=getattr(cls,'get_%s'%_get)method_name='%s_by_%s'%(_get,_by)method=getattr(cls,'_by_%s'%_by)(_get_method)cls._add_method(method_name=method_name,method=method,signature=cls._get_method_signature,doc=_get_method.__doc__,)@classmethoddef_add_method(cls,method_name,method,signature=None,doc=None):common.add_method(cls,method_name,method,signature=signature,doc=doc,)
[docs]defgenerate_df_records(self,by_source:bool=False,with_references:bool=False,):""" Yields interaction records. It is a generator because one edge can be represented by one or more records depending on the signs and directions and other parameters Args by_source: Yield separate records by resources. This way the node pairs will be redundant and you need to group later if you want unique interacting pairs. By default is ``False`` because for most applications unique interactions are preferred. If ``False`` the *refrences* field will still be present but with ``None`` values. with_references: Include the literature references. By default is ``False`` because you rarely need these and they increase the data size significantly. """defsource_add_via(source,via):return'%s%s'%(source,'_%s'%viaifviaelse'')defiter_sources(evs):sources=evs.get_resource_names_via()ifby_source:forsource,viainsources:refs=({ref.pmidforrefinself.get_references(resources=source,interaction_type=interaction_type,via=via,)}ifwith_referenceselseNone)_source=source_add_via(source,via)yield_source,refselse:_sources={source_add_via(source,via)forsource,viainsources}refs=({ref.pmidforrefinself.get_references(resources={s[0]forsinsources},interaction_type=interaction_type,)}ifwith_referenceselseNone)if_sources:yield_sources,refsforinteraction_typeinself.get_interaction_types():dmodels=(self.get_data_models(interaction_type=interaction_type))dmodels=dmodelsifby_sourceelse(dmodels,)fordata_modelindmodels:evs_undirected=self.get_evidences(direction='undirected',interaction_type=interaction_type,data_model=data_model,)for_dirin(self.a_b,self.b_a):evs_dir=self.get_evidences(direction=_dir,interaction_type=interaction_type,data_model=data_model,)evs_without_sign=evs_dir.__copy__()for_effect,effectinzip((1,-1),('positive','negative')):evs_sign=self.get_evidences(direction=_dir,effect=effect,interaction_type=interaction_type,data_model=data_model,)# to make sure we keep all references:evs_sign+=evs_sign.intersection(evs_dir)evs_without_sign-=evs_signevs_undirected-=evs_signforsources,refsiniter_sources(evs_sign):yieldInteractionDataFrameRecord(id_a=_dir[0].identifier,id_b=_dir[1].identifier,type_a=_dir[0].entity_type,type_b=_dir[1].entity_type,directed=True,effect=_effect,type=interaction_type,dmodel=data_model,sources=sources,references=refs,)ifevs_without_sign:evs_undirected-=evs_without_signforsources,refsiniter_sources(evs_without_sign):yieldInteractionDataFrameRecord(id_a=_dir[0].identifier,id_b=_dir[1].identifier,type_a=_dir[0].entity_type,type_b=_dir[1].entity_type,directed=True,effect=0,type=interaction_type,dmodel=data_model,sources=sources,references=refs,)ifevs_undirected:forsources,refsiniter_sources(evs_undirected):yieldInteractionDataFrameRecord(id_a=self.a.identifier,id_b=self.b.identifier,type_a=self.a.entity_type,type_b=self.b.entity_type,directed=False,effect=0,type=interaction_type,dmodel=data_model,sources=sources,references=refs,)
[docs]defasdict(self,direction:tuple)->dict:""" Dictionary representation of the evidences. """direction=self.a_bifself.a_b==directionelseself.b_areturn{'id_a':str(direction[0].identifier),'id_b':str(direction[1].identifier),'positive':self.positive[direction].asdict(),'negative':self.negative[direction].asdict(),'directed':self.unknown_effect[direction].asdict(),'undirected':self.direction['undirected'].asdict(),}
[docs]defserialize_attrs(self,direction:tuple|str|None=None)->str:""" Serialize the resource specific attributes into a JSON string. """evs=self.evidencesifnotdirectionelseself.direction[direction]returnevs.serialize_attrs()
[docs]defserialize_evidences(self,direction:tuple)->str:""" Serialize the evidences into a JSON string. """returnself._serialize(self.asdict(direction=direction))
[docs]defget_attr(self,resource:str,key:str,direction:tuple|str|None=None,):""" Extracts the values of one specific attribute. Args resource: Name of the resource. key: Name of the attribute. direction: Direction(s) to consider, either a tuple of entities or entity names, or the string `undirected`. Returns Depends on the arguments. The value of the attribute if direction is defined. Otherwise a dict with the value of the attribute for each direction. The value of the attribute is `None` if the resource or the attribute does not belong to this interaction. """ifdirection:returnself._get_attr(resource,key,direction)else:returndict((d,self._get_attr(resource,key,d))fordinself.direction.keys())
[docs]defdorothea_levels(self,direction:str|tuple|None=None):""" Retrieves the DoRothEA confidence levels. Args direction: Direction(s) to consider, either a tuple of entities or entity names, or the string `undirected`. Returns List of unique single letter strings representing the five confidence levels (A-E). """directions=(direction,)ifdirectionelse(self.a_b,self.b_a)returnsorted({levelfordirectionindirectionsforlevelin(self._get_attr('DoRothEA','level',direction)or())})
[docs]defdorothea_level(self,direction:str|tuple,)->Literal['A','B','C','D','E']:""" DoRothEA confidence level for one direction as a single letter. Some interactions might have multiple levels due to the ambiguous nature of translating gene symbols to UniProt IDs. Here we take the highest level and drop the rest. For interactions without DoRothEA levels None is returned. """levels=self.dorothea_levels(direction=direction)returncommon.first(levels)