# -*- coding: utf-8 -*-
"""This module helps handle node data dictionaries."""
from typing import Any, List, Mapping, Union
from pyparsing import ParseResults
from .constants import (
CONCEPT,
FRAGMENT,
FRAGMENT_DESCRIPTION,
FRAGMENT_START,
FRAGMENT_STOP,
FUNCTION,
FUSION,
FUSION_MISSING,
FUSION_REFERENCE,
FUSION_START,
FUSION_STOP,
GMOD,
HGVS,
IDENTIFIER,
KIND,
MEMBERS,
NAME,
NAMESPACE,
PARTNER_3P,
PARTNER_5P,
PMOD,
PMOD_CODE,
PMOD_POSITION,
PRODUCTS,
RANGE_3P,
RANGE_5P,
REACTANTS,
REACTION,
VARIANTS,
XREFS,
)
from .dsl import (
FUNC_TO_DSL,
FUNC_TO_FUSION_DSL,
FUNC_TO_LIST_DSL,
BaseAbundance,
BaseEntity,
CentralDogma,
EnumeratedFusionRange,
Fragment,
FusionBase,
FusionRangeBase,
GeneModification,
Hgvs,
ListAbundance,
MissingFusionRange,
ProteinModification,
Reaction,
Variant,
)
__all__ = [
"parse_result_to_dsl",
]
[docs]def parse_result_to_dsl(tokens) -> BaseEntity:
"""Convert a ParseResult to a PyBEL DSL object.
:type tokens: dict or pyparsing.ParseResults
"""
# if MODIFIER in tokens:
# return parse_result_to_dsl(tokens[TARGET])
if REACTION == tokens[FUNCTION]:
return _reaction_po_to_dict(tokens)
elif VARIANTS in tokens:
return _variant_po_to_dict(tokens)
elif MEMBERS in tokens:
if CONCEPT in tokens:
return _list_po_with_concept_to_dict(tokens)
return _list_po_to_dict(tokens)
elif FUSION in tokens:
return _fusion_to_dsl(tokens)
return _simple_po_to_dict(tokens)
def _fusion_to_dsl(tokens) -> FusionBase:
"""Convert a PyParsing data dictionary to a PyBEL fusion data dictionary.
:param tokens: A PyParsing data dictionary representing a fusion
:type tokens: ParseResult
"""
func = tokens[FUNCTION]
fusion_dsl = FUNC_TO_FUSION_DSL[func]
member_dsl = FUNC_TO_DSL[func]
partner_5p = tokens[FUSION][PARTNER_5P]
partner_5p_concept = partner_5p[CONCEPT] if CONCEPT in tokens[FUSION][PARTNER_5P] else partner_5p
partner_5p_node = member_dsl(
namespace=partner_5p_concept[NAMESPACE],
name=partner_5p_concept[NAME],
identifier=partner_5p_concept.get(IDENTIFIER),
xrefs=partner_5p.get(XREFS),
)
partner_3p = tokens[FUSION][PARTNER_3P]
partner_3p_concept = partner_3p[CONCEPT] if CONCEPT in tokens[FUSION][PARTNER_3P] else partner_3p
partner_3p_node = member_dsl(
namespace=partner_3p_concept[NAMESPACE],
name=partner_3p_concept[NAME],
identifier=partner_3p_concept.get(IDENTIFIER),
xrefs=partner_3p.get(XREFS),
)
range_5p = _fusion_range_to_dsl(tokens[FUSION][RANGE_5P])
range_3p = _fusion_range_to_dsl(tokens[FUSION][RANGE_3P])
return fusion_dsl(
partner_5p=partner_5p_node,
partner_3p=partner_3p_node,
range_5p=range_5p,
range_3p=range_3p,
)
def _fusion_range_to_dsl(tokens) -> FusionRangeBase:
"""Convert a PyParsing data dictionary into a PyBEL.
:type tokens: ParseResult
"""
if FUSION_MISSING in tokens:
return MissingFusionRange()
return EnumeratedFusionRange(
reference=tokens[FUSION_REFERENCE],
start=tokens[FUSION_START],
stop=tokens[FUSION_STOP],
)
def _simple_po_to_dict(tokens) -> BaseAbundance:
"""Convert a simple named entity to a DSL object.
:type tokens: ParseResult
"""
dsl = FUNC_TO_DSL.get(tokens[FUNCTION])
if dsl is None:
raise ValueError("invalid tokens: {}".format(tokens))
concept = tokens[CONCEPT]
return dsl(
namespace=concept[NAMESPACE],
name=concept.get(NAME),
identifier=concept.get(IDENTIFIER),
xrefs=tokens.get(XREFS),
)
def _variant_po_to_dict(tokens) -> CentralDogma:
"""Convert a PyParsing data dictionary to a central dogma abundance (i.e., Protein, RNA, miRNA, Gene).
:type tokens: ParseResult
"""
dsl = FUNC_TO_DSL.get(tokens[FUNCTION])
if dsl is None:
raise ValueError("invalid tokens: {}".format(tokens))
concept = tokens[CONCEPT]
return dsl(
namespace=concept[NAMESPACE],
name=concept[NAME],
identifier=concept.get(IDENTIFIER),
xrefs=tokens.get(XREFS),
variants=[_variant_to_dsl_helper(variant_tokens) for variant_tokens in tokens[VARIANTS]],
)
def _variant_to_dsl_helper(tokens) -> Variant:
"""Convert variant tokens to DSL objects.
:type tokens: ParseResult
"""
kind = tokens[KIND]
if kind == HGVS:
return Hgvs(tokens[HGVS])
if kind == GMOD:
concept = tokens[CONCEPT]
return GeneModification(
name=concept[NAME],
namespace=concept[NAMESPACE],
identifier=concept.get(IDENTIFIER),
xrefs=tokens.get(XREFS),
)
if kind == PMOD:
concept = tokens[CONCEPT]
return ProteinModification(
name=concept[NAME],
namespace=concept[NAMESPACE],
identifier=concept.get(IDENTIFIER),
xrefs=tokens.get(XREFS),
code=tokens.get(PMOD_CODE),
position=tokens.get(PMOD_POSITION),
)
if kind == FRAGMENT:
start, stop = tokens.get(FRAGMENT_START), tokens.get(FRAGMENT_STOP)
return Fragment(
start=start,
stop=stop,
description=tokens.get(FRAGMENT_DESCRIPTION),
)
raise ValueError("invalid fragment kind: {}".format(kind))
def _reaction_po_to_dict(tokens) -> Reaction:
"""Convert a reaction parse object to a DSL.
:type tokens: ParseResult
"""
return Reaction(
reactants=_parse_tokens_list(tokens[REACTANTS]),
products=_parse_tokens_list(tokens[PRODUCTS]),
)
def _list_po_with_concept_to_dict(tokens: Union[ParseResults, Mapping[str, Any]]) -> ListAbundance:
"""Convert a list parse object to a node.
:type tokens: ParseResult
"""
func = tokens[FUNCTION]
dsl = FUNC_TO_LIST_DSL[func]
members = _parse_tokens_list(tokens[MEMBERS])
concept = tokens[CONCEPT]
return dsl(
members=members,
namespace=concept[NAMESPACE],
name=concept.get(NAME),
identifier=concept.get(IDENTIFIER),
xrefs=tokens.get(XREFS),
)
def _list_po_to_dict(tokens) -> ListAbundance:
"""Convert a list parse object to a node.
:type tokens: ParseResult
"""
func = tokens[FUNCTION]
dsl = FUNC_TO_LIST_DSL[func]
members = _parse_tokens_list(tokens[MEMBERS])
return dsl(members)
def _parse_tokens_list(tokens) -> List[BaseEntity]:
"""Convert a PyParsing result to a reaction.
:type tokens: ParseResult
"""
return [parse_result_to_dsl(token) for token in tokens]