Repository: pybel/pybel

Issue:
pybel.tokens.parse_result_to_dsl doesn't capture 'concept' information
### Current behavior
When passing a pybel Entity to `parse_result_to_dsl()`, the 'concept' entries don't get mapped to a corresponding 'entity' parameter in the returned node. For example, when passing `{'function': 'Complex', 'members': [{}, {}], 'concept': {'namespace': 'hgnc', 'name': 'ca'}}` to the function, the BEL complex returned has an `entity` value of `None`, as shown in the following image.

![image](https://user-images.githubusercontent.com/45149156/90273727-69e91900-de2d-11ea-9b09-fbd28a0f55ac.png)

### Expected behavior
Expected the function to return an `entity` value consistent with the node schema defined in the schema sub-module.


Comments:

Patch:
diff --git a/src/pybel/tokens.py b/src/pybel/tokens.py
index 2a43df6b..9c34502d 100644
--- a/src/pybel/tokens.py
+++ b/src/pybel/tokens.py
@@ -2,7 +2,9 @@
 
 """This module helps handle node data dictionaries."""
 
-from typing import List
+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,
@@ -34,6 +36,8 @@ def parse_result_to_dsl(tokens) -> BaseEntity:
         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:
@@ -196,6 +200,25 @@ def _reaction_po_to_dict(tokens) -> Reaction:
     )
 
 
+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.
 


Test patch:
diff --git a/tests/test_dsl.py b/tests/test_dsl.py
index 76d8a9e9..bb177dd0 100644
--- a/tests/test_dsl.py
+++ b/tests/test_dsl.py
@@ -4,6 +4,7 @@
 
 import unittest
 
+import pybel.constants as pc
 from pybel import BELGraph
 from pybel.constants import NAME
 from pybel.dsl import (
@@ -12,6 +13,7 @@ from pybel.dsl import (
 )
 from pybel.language import Entity
 from pybel.testing.utils import n
+from pybel.tokens import parse_result_to_dsl
 from pybel.utils import ensure_quotes
 
 
@@ -210,5 +212,20 @@ class TestCentralDogma(unittest.TestCase):
             Reaction([], [])
 
 
+class TestParse(unittest.TestCase):
+    """Test that :func:`parse_result_to_dsl` works correctly."""
+
+    def test_named_complex(self):
+        x = ComplexAbundance(namespace='a', identifier='b', members=[
+            Protein(namespace='c', identifier='d'),
+            Protein(namespace='c', identifier='e'),
+        ])
+
+        y = parse_result_to_dsl(dict(x))
+        self.assertIsInstance(y, ComplexAbundance)
+        self.assertIn(pc.MEMBERS, y)
+        self.assertIn(pc.CONCEPT, y)
+
+
 if __name__ == '__main__':
     unittest.main()