Ejemplo n.º 1
0
 def test_add_opaque_aspect_invalid_type(self):
     net_cx = NiceCXNetwork()
     try:
         net_cx.add_opaque_aspect('foo', 'invalid data')
         self.fail('Expected Exception')
     except Exception as e:
         self.assertEqual('Provided input was not of type list.', str(e))
Ejemplo n.º 2
0
class NiceCXBuilder(object):
    def __init__(self, cx=None, server=None, username='******', password='******', uuid=None, networkx_G=None, data=None, **attr):
        from ndex2.nice_cx_network import NiceCXNetwork

        self.nice_cx = NiceCXNetwork(user_agent='niceCx Builder')
        self.node_id_lookup = {}
        self.node_id_counter = 0
        self.edge_id_counter = 0

        self.node_inventory = {}
        self.node_attribute_inventory = []
        self.node_attribute_map = {}

        self.edge_inventory = {}
        self.edge_attribute_inventory = []
        self.edge_attribute_map = {}

        self.opaque_aspect_inventory = []

        self.context_inventory = []

        self.network_attribute_inventory = {}

        self.user_base64 = None
        self.username = None
        self.password = None
        if username and password:
            self.username = username
            self.password = password
            if sys.version_info.major == 3:
                encode_string = '%s:%s' % (username, password)
                byte_string = encode_string.encode()
                self.user_base64 = base64.b64encode(byte_string)#.replace('\n', '')
            else:
                self.user_base64 = base64.encodestring('%s:%s' % (username, password)).replace('\n', '')

    def set_context(self, context):
        """
        Set the @context information of the network.  This information maps namespace prefixes to their defining URIs

        Example:

            ``set_context({'pmid': 'https://www.ncbi.nlm.nih.gov/pubmed/'})``

        :param context: dict of name, URI pairs
        :type context: dict
        :return: None
        :rtype: none
        """
        if isinstance(context, dict):
            self.context_inventory = context
        elif isinstance(context, list):
            if len(context) > 0:
                self.context_inventory = context[0]

    def set_name(self, network_name):
        """
        Set the network name

        :param network_name: Network name
        :type network_name: string
        :return: None
        :rtype:none
        """

        self.network_attribute_inventory['name'] = {'n': 'name', 'v': network_name, 'd': 'string'}

    def add_network_attribute(self, name=None, values=None, type=None, cx_element=None):
        """
        Add an attribute to the network

        :param name: Name of the attribute
        :type name: str
        :param values:  The value(s) of the attribute
        :type values: One of the allowable CX types.  See `Supported data types`_
        :param type: They type of data supplied in values. Default is string.  See `Supported data types`_
        :type type: str
        :return: None
        :rtype: None
        """

        add_this_network_attribute = {'n': name, 'v': values}
        if type:
            add_this_network_attribute['d'] = type

        self.network_attribute_inventory[name] = add_this_network_attribute

    def add_node(self, name=None, represents=None, id=None, data_type=None, map_node_ids=False):
        """
        Adds a new node with the corresponding name and represents (external id)

        :param node_name: Name of the node
        :type node_name: str
        :param represents: Representation of the node (alternate identifier)
        :type represents: str
        :param id:
        :type id:
        :return: Node ID
        :rtype: int
        """
        if self.node_inventory.get(name) is not None:
            return self.node_inventory.get(name).get('@id')

        if id:
            node_id = id
        else:
            node_id = self.node_id_counter
            self.node_id_counter += 1

        add_this_node = {'@id': node_id, 'n': name}
        if represents:
            add_this_node['r'] = represents
        if data_type:
            add_this_node['d'] = data_type

        self.node_inventory[name] = add_this_node

        if map_node_ids:
            self.node_id_lookup[name] = node_id

        return node_id

    def add_edge(self, source=None, target=None, interaction=None, id=None):
        """
        Adds a new edge in the network by specifying source-interaction-target

        :param source: The source node of this edge, either its id or the node object itself.
        :type source: int, dict (with @id property)
        :param target: The target node of this edge, either its id or the node object itself.
        :type target: int, dict (with @id property)
        :param interaction: The interaction that describes the relationship between the source and target nodes
        :type interaction: str
        :param id: Edge id for this edge.  If none is provided the builder will create one
        :type id: int
        :return: Edge ID
        :rtype: int
        """

        if id is not None:
            edge_id = id
        else:
            edge_id = self.edge_id_counter
            self.edge_id_counter += 1

        add_this_edge = {'@id': edge_id, 's': source, 't': target}
        if interaction:
            add_this_edge['i'] = interaction
        else:
            add_this_edge['i'] = 'interacts-with'

        self.edge_inventory[edge_id] = add_this_edge

        return edge_id

    def add_node_attribute(self, property_of, name, values, type=None):
        """
        Set an attribute of a node, where the node may be specified by its id or passed in as a node dict.

        :param property_of: Node ID to add the attribute to
        :type property_of: int
        :param name: Attribute name
        :type name: str
        :param value: A value or list of values of the attribute
        :type value: list, string, int or float
        :param type: The datatype of the attribute values, defaults is string.  See `Supported data types`_
        :type type: str
        :return: None
        :rtype: None
        """


        if property_of is None:
            raise TypeError('Node value is None')

        if name is None:
            raise TypeError('Property name is None')

        if values is None:
            raise TypeError('Attribute value is None')

        add_this_node_attribute = {'po': property_of, 'n': name, 'v': values}


        if self.node_attribute_map.get(property_of) is None:
            self.node_attribute_map[property_of] = {}
        elif self.node_attribute_map[property_of].get(name) is not None:
            # TODO - Raise warning/exception for duplicate attribute
            return

        if type:
            if type == 'float' or type == 'double':
                type = 'double'
                try:
                    if not isinstance(values, float):
                        add_this_node_attribute['v'] = float(values)
                except ValueError as e:
                    raise ValueError('Value was not of type %s' % type)
            if type == 'list_of_float' or type == 'list_of_double':
                try:
                    if isinstance(values, list):
                        for value in values:
                            if not isinstance(value, float):
                                value = float(value)
                except ValueError as e:
                    raise ValueError('Value was not of type %s' % type)

                type = 'list_of_double'

            add_this_node_attribute['d'] = type
        else:
            use_this_value, attr_type = self._infer_data_type(values)
            add_this_node_attribute['v'] = use_this_value
            add_this_node_attribute['d'] = attr_type

        if add_this_node_attribute['v'] is not None:
            self.node_attribute_inventory.append(add_this_node_attribute)
            self.node_attribute_map[property_of][name] = True

    def add_edge_attribute(self, property_of=None, name=None, values=None, type=None):
        """
        Set the value(s) of attribute of an edge, where the edge may be specified by its id or passed in an object.

        Example:

            ``set_edge_attribute(0, 'weight', 0.5, type='float')``

            or

            ``set_edge_attribute(edge, 'Disease', 'Atherosclerosis')``

        :param property_of: Edge to add the attribute to
        :type property_of: int or edge dict with @id attribute
        :param name: Attribute name
        :type name: str
        :param values: A value or list of values of the attribute
        :type values: list, string, int or float
        :param type: The datatype of the attribute values, defaults to the python datatype of the values.  See `Supported data types`_
        :type type: str
        :return: None
        :rtype: None
        """
        if property_of is None:
            raise TypeError('Edge value is None')

        if name is None:
            raise TypeError('Property name is None')

        if values is None:
            raise TypeError('Attribute value is None')

        add_this_edge_attribute = {'po': property_of, 'n': name, 'v': values}

        if self.edge_attribute_map.get(property_of) is None:
            self.edge_attribute_map[property_of] = {}
        elif self.edge_attribute_map[property_of].get(name) is not None:
            return

        if type:
            if type == 'float' or type == 'double':
                type = 'double'
                try:
                    if not isinstance(values, float):
                        add_this_edge_attribute['v'] = float(values)
                except ValueError as e:
                    raise ValueError('Value was not of type %s' % type)
            if type == 'list_of_float' or  type == 'list_of_double':
                try:
                    if isinstance(values, list):
                        for value in values:
                            if not isinstance(value, float):
                                value = float(value)
                except ValueError as e:
                    raise ValueError('Value was not of type %s' % type)

                type = 'list_of_double'
            add_this_edge_attribute['d'] = type
        else:
            use_this_value, attr_type = self._infer_data_type(values)
            add_this_edge_attribute['v'] = use_this_value
            add_this_edge_attribute['d'] = attr_type

        if add_this_edge_attribute['v'] is not None:
            self.edge_attribute_inventory.append(add_this_edge_attribute)
            self.edge_attribute_map[property_of][name] = True

    def add_opaque_aspect(self, oa_name, oa_list):
        self.opaque_aspect_inventory.append({oa_name: oa_list})

    #===================================
    # methods to add data by fragment
    #===================================
    def _add_network_attributes_from_fragment(self, fragment):
        self.nice_cx.networkAttributes.append(fragment)

    def _add_node_from_fragment(self, fragment):
        self.nice_cx.nodes[fragment.get('@id')] = fragment

    def _add_edge_from_fragment(self, fragment):
        self.nice_cx.edges[fragment.get('@id')] = fragment

    def _add_node_attribute_from_fragment(self, fragment):
        if self.nice_cx.nodeAttributes.get(fragment.get('po')) is None:
            self.nice_cx.nodeAttributes[fragment.get('po')] = []

        self.nice_cx.nodeAttributes[fragment.get('po')].append(fragment)

    def _add_edge_attribute_from_fragment(self, fragment):
        if self.nice_cx.edgeAttributes.get(fragment.get('po')) is None:
            self.nice_cx.edgeAttributes[fragment.get('po')] = []

        self.nice_cx.edgeAttributes[fragment.get('po')].append(fragment)

    def _add_citation_from_fragment(self, fragment):
        self.nice_cx.citations[fragment.get('@id')] = fragment

    def _add_supports_from_fragment(self, fragment):
        self.nice_cx.supports[fragment.get('@id')] = fragment

    def _add_edge_supports_from_fragment(self, fragment):
        for po_id in fragment.get('po'):
            self.nice_cx.edgeSupports[po_id] = fragment.get('supports')

    def _add_node_citations_from_fragment(self, fragment):
        for po_id in fragment.get('po'):
            self.nice_cx.nodeCitations[po_id] = fragment.get('citations')

    def _add_edge_citations_from_fragment(self, fragment):
        for po_id in fragment.get('po'):
            self.nice_cx.edgeCitations[po_id] = fragment.get('citations')

    def get_nice_cx(self):
        #==========================
        # ADD CONTEXT
        #==========================
        if isinstance(self.context_inventory, dict):
            self.nice_cx.set_context(self.context_inventory)
        else:
            for c in self.context_inventory:
                self.nice_cx.set_context(c)

        #=============================
        # ASSEMBLE NETWORK ATTRIBUTES
        #=============================
        #{'n': 'name', 'v': network_name, 'd': 'string'}
        for k, v in self.network_attribute_inventory.items():
            self.nice_cx.add_network_attribute(name=v.get('n'), values=v.get('v'), type=v.get('d'))

        #==========================
        # ASSEMBLE NODES
        #==========================
        for k, v in self.node_inventory.items():
            self.nice_cx.nodes[v.get('@id')] = v

        #==========================
        # ASSEMBLE NODE ATTRIBUTES
        #==========================
        for a in self.node_attribute_inventory:
            property_of = a.get('po')

            if self.nice_cx.nodeAttributes.get(property_of) is None:
                self.nice_cx.nodeAttributes[property_of] = []

            self.nice_cx.nodeAttributes[property_of].append(a)

        #==========================
        # ASSEMBLE EDGES
        #==========================
        for k, v in self.edge_inventory.items():
            self.nice_cx.edges[k] = v

        #==========================
        # ASSEMBLE EDGE ATTRIBUTES
        #==========================
        for a in self.edge_attribute_inventory:
            property_of = a.get('po')

            if self.nice_cx.edgeAttributes.get(property_of) is None:
                self.nice_cx.edgeAttributes[property_of] = []

            self.nice_cx.edgeAttributes[property_of].append(a)

        #==========================
        # ASSEMBLE OPAQUE ASPECTS
        #==========================
        for oa in self.opaque_aspect_inventory:
            for k, v in oa.items():
                self.nice_cx.add_opaque_aspect(k, v)

        return self.nice_cx

    def get_frag_from_list_by_key(self, cx, key):
        return_list = []
        for aspect in cx:
            if key in aspect:
                if isinstance(aspect[key], list):
                    for a_item in aspect[key]:
                        return_list.append(a_item)
                else:
                    return_list.append(aspect[key])

        return return_list

    def load_aspect(self, aspect_name):
        #with open('Signal1.cx', mode='r') as cx_f:
        with open('network1.cx', mode='r') as cx_f:
            aspect_json = json.loads(cx_f.read())
            for aspect in aspect_json:
                if aspect.get(aspect_name) is not None:
                    return aspect.get(aspect_name)

    def stream_all_aspects(self, uuid):
        return ijson.items(urlopen('http://dev2.ndexbio.org/v2/network/' + uuid), 'item')

    def stream_aspect(self, uuid, aspect_name):
        if aspect_name == 'metaData':
            print('http://dev2.ndexbio.org/v2/network/' + uuid + '/aspect')
            md_response = requests.get('http://dev2.ndexbio.org/v2/network/' + uuid + '/aspect')
            json_respone = md_response.json()
            return json_respone.get('metaData')
        else:
            #password_mgr = HTTPPasswordMgrWithDefaultRealm()

            #top_level_url = 'http://dev2.ndexbio.org'
            #password_mgr.add_password(None, top_level_url, self.username, self.password)
            #handler = HTTPBasicAuthHandler(password_mgr)
            #opener = build_opener(handler)
            #install_opener(opener)





            # Create an OpenerDirector with support for Basic HTTP Authentication...
            #auth_handler = HTTPBasicAuthHandler()
            #auth_handler.add_password(None, 'http://dev2.ndexbio.org', 'scratch', 'scratch')
            #opener = build_opener(auth_handler)
            # ...and install it globally so it can be used with urlopen.
            #install_opener(opener)


            request = Request('http://dev2.ndexbio.org/v2/network/' + uuid + '/aspect/' + aspect_name)
            base64string = base64.b64encode('%s:%s' % ('scratch', 'scratch'))
            request.add_header("Authorization", "Basic %s" % base64string)
            #result = urllib2.urlopen(request)


            urlopen_result = None
            try:
                urlopen_result = urlopen(request) #'http://dev2.ndexbio.org/v2/network/' + uuid + '/aspect/' + aspect_name)
            except HTTPError as e:
                print(e.code)
                return []
            except URLError as e:
                print('Other error')
                print('URL Error %s' % e.message())
                return []

            return ijson.items(urlopen_result, 'item')

    def stream_aspect_raw(self, uuid, aspect_name):
        return ijson.parse(urlopen('http://dev2.ndexbio.org/v2/network/' + uuid + '/aspect/' + aspect_name))

    def _infer_data_type(self, val, split_string=False):
        if val is None:
            return None, None

        attr_type = 'string'

        if split_string:
            if isinstance(val, str):
                val = val.replace('"', '')
                if ',' in val:
                    val = val.split(',')
                elif ';' in val:
                    val = val.split(';')

        processed_value = val

        if isinstance(val, float) or isinstance(val, np.float) or isinstance(val, np.double):
            if math.isnan(val):
                # do something (skip?)
                processed_value = None
            elif math.isinf(val):
                processed_value = 'INFINITY'
            attr_type = 'double'  # CX spec dropped support for float and instead uses double precision
        elif isinstance(val, int) or isinstance(val, np.int):
            attr_type = 'integer'
        elif isinstance(val, list):
            if len(val) > 0:
                if isinstance(val[0], float) or isinstance(val[0], np.float) or isinstance(val[0], np.double):
                    attr_type = 'list_of_double'
                elif isinstance(val[0], int) or isinstance(val[0], np.int):
                    attr_type = 'list_of_integer'
                else:
                    attr_type = 'list_of_string'

        return processed_value, attr_type
Ejemplo n.º 3
0
class NiceCXBuilder(object):
    def __init__(self,
                 cx=None,
                 server=None,
                 username='******',
                 password='******',
                 uuid=None,
                 networkx_G=None,
                 data=None,
                 **attr):
        from ndex2.nice_cx_network import NiceCXNetwork

        self.logger = logging.getLogger(__name__)

        self.nice_cx = NiceCXNetwork(user_agent='niceCx Builder')
        self.node_id_lookup = {}
        self.node_id_counter = 0
        self.edge_id_counter = 0
        self.max_node_id = 0
        self.max_edge_id = 0

        self.node_inventory = {}
        self.node_attribute_inventory = []
        self.node_attribute_map = {}

        self.edge_inventory = {}
        self.edge_attribute_inventory = []
        self.edge_attribute_map = {}

        self.opaque_aspect_inventory = []

        self.context_inventory = []

        self.network_attribute_inventory = {}

        self.user_base64 = None
        self.username = None
        self.password = None
        if username and password:
            self.username = username
            self.password = password
            if sys.version_info.major == 3:
                encode_string = '%s:%s' % (username, password)
                byte_string = encode_string.encode()
                self.user_base64 = base64.b64encode(
                    byte_string)  #.replace('\n', '')
            else:
                self.user_base64 = base64.encodestring(
                    '%s:%s' % (username, password)).replace('\n', '')

    def set_context(self, context):
        """
        Set the @context information of the network.  This information
        maps namespace prefixes to their defining URIs

        Example:

            ``set_context({'pmid': 'https://www.ncbi.nlm.nih.gov/pubmed/'})``

        :param context: dict of name, URI pairs
        :type context: dict
        :return: None
        :rtype: none
        """
        if isinstance(context, dict):
            self.context_inventory = context
        elif isinstance(context, list):
            if len(context) > 0:
                self.context_inventory = context[0]

    def set_name(self, network_name):
        """
        Set the network name

        :param network_name: Network name
        :type network_name: string
        :return: None
        :rtype:none
        """

        self.network_attribute_inventory['name'] = {
            'n': 'name',
            'v': network_name,
            'd': 'string'
        }

    def add_network_attribute(self,
                              name=None,
                              values=None,
                              type=None,
                              cx_element=None):
        """
        Add an attribute to the network

        :param name: Name of the attribute
        :type name: str
        :param values:  The value(s) of the attribute
        :type values: One of the allowable CX types.  See `Supported data types`_
        :param type: They type of data supplied in values. Default is string.  See `Supported data types`_
        :type type: str
        :return: None
        :rtype: None
        """
        add_this_network_attribute = {'n': name, 'v': values}
        if type:
            add_this_network_attribute['d'] = type

        self.network_attribute_inventory[name] = add_this_network_attribute

    def add_node(self,
                 name=None,
                 represents=None,
                 id=None,
                 data_type=None,
                 map_node_ids=False):
        """
        Adds a new node with the corresponding name and represents (external id)

        :param node_name: Name of the node
        :type node_name: str
        :param represents: Representation of the node (alternate identifier)
        :type represents: str
        :param id:
        :type id:
        :return: Node ID
        :rtype: int
        """
        if self.node_inventory.get(name) is not None:
            return self.node_inventory.get(name).get('@id')

        if id:
            node_id = id
        else:
            node_id = self.node_id_counter
            self.node_id_counter += 1

        if node_id > self.max_node_id:
            self.max_node_id = node_id

        add_this_node = {'@id': node_id, 'n': name}
        if represents:
            add_this_node['r'] = represents
        if data_type:
            add_this_node['d'] = data_type

        self.node_inventory[name] = add_this_node

        if map_node_ids:
            self.node_id_lookup[name] = node_id

        return node_id

    def add_edge(self, source=None, target=None, interaction=None, id=None):
        """
        Adds a new edge in the network by specifying source-interaction-target

        :param source: The source node of this edge, either its id or the node object itself.
        :type source: int, dict (with @id property)
        :param target: The target node of this edge, either its id or the node object itself.
        :type target: int, dict (with @id property)
        :param interaction: The interaction that describes the relationship between the source and target nodes
        :type interaction: str
        :param id: Edge id for this edge.  If none is provided the builder will create one
        :type id: int
        :return: Edge ID
        :rtype: int
        """

        if id is not None:
            edge_id = id
        else:
            edge_id = self.edge_id_counter
            self.edge_id_counter += 1

        if edge_id > self.max_edge_id:
            self.max_edge_id = edge_id

        add_this_edge = {'@id': edge_id, 's': source, 't': target}
        if interaction:
            add_this_edge['i'] = interaction
        else:
            add_this_edge['i'] = 'interacts-with'

        self.edge_inventory[edge_id] = add_this_edge

        return edge_id

    def add_node_attribute(self, property_of, name, values, type=None):
        """
        Set an attribute of a node, where the node may be specified by its id or passed in as a node dict.

        :param property_of: Node ID to add the attribute to
        :type property_of: int
        :param name: Attribute name
        :type name: str
        :param value: A value or list of values of the attribute
        :type value: list, string, int or float
        :param type: The datatype of the attribute values, defaults is string.  See `Supported data types`_
        :type type: str
        :return: None
        :rtype: None
        """

        if property_of is None:
            raise TypeError('Node value is None')

        if name is None:
            raise TypeError('Property name is None')

        if values is None:
            raise TypeError('Attribute value is None')

        add_this_node_attribute = {'po': property_of, 'n': name, 'v': values}

        if self.node_attribute_map.get(property_of) is None:
            self.node_attribute_map[property_of] = {}
        elif self.node_attribute_map[property_of].get(name) is not None:
            # TODO - Raise warning/exception for duplicate attribute
            return

        if type:
            if type == 'float' or type == 'double':
                type = 'double'
                try:
                    if not isinstance(values, float):
                        add_this_node_attribute['v'] = float(values)
                except ValueError as e:
                    raise ValueError('Value was not of type %s' % type)
            if type == 'list_of_float' or type == 'list_of_double':
                try:
                    if isinstance(values, list):
                        for value in values:
                            if not isinstance(value, float):
                                value = float(value)
                except ValueError as e:
                    raise ValueError('Value was not of type %s' % type)

                type = 'list_of_double'

            add_this_node_attribute['d'] = type
        else:
            use_this_value, attr_type = self._infer_data_type(values)
            add_this_node_attribute['v'] = use_this_value
            add_this_node_attribute['d'] = attr_type

        if add_this_node_attribute['v'] is not None:
            self.node_attribute_inventory.append(add_this_node_attribute)
            self.node_attribute_map[property_of][name] = True

    def add_edge_attribute(self,
                           property_of=None,
                           name=None,
                           values=None,
                           type=None):
        """
        Set the value(s) of attribute of an edge, where the edge may be specified by its id or passed in an object.

        Example:

            ``set_edge_attribute(0, 'weight', 0.5, type='float')``

            or

            ``set_edge_attribute(edge, 'Disease', 'Atherosclerosis')``

        :param property_of: Edge to add the attribute to
        :type property_of: int or edge dict with @id attribute
        :param name: Attribute name
        :type name: str
        :param values: A value or list of values of the attribute
        :type values: list, string, int or float
        :param type: The datatype of the attribute values, defaults to the python datatype of the values.  See `Supported data types`_
        :type type: str
        :return: None
        :rtype: None
        """
        if property_of is None:
            raise TypeError('Edge value is None')

        if name is None:
            raise TypeError('Property name is None')

        if values is None:
            raise TypeError('Attribute value is None')

        add_this_edge_attribute = {'po': property_of, 'n': name, 'v': values}

        if self.edge_attribute_map.get(property_of) is None:
            self.edge_attribute_map[property_of] = {}
        elif self.edge_attribute_map[property_of].get(name) is not None:
            return

        if type:
            if type == 'float' or type == 'double':
                type = 'double'
                try:
                    if not isinstance(values, float):
                        add_this_edge_attribute['v'] = float(values)
                except ValueError as e:
                    raise ValueError('Value was not of type %s' % type)
            if type == 'list_of_float' or type == 'list_of_double':
                try:
                    if isinstance(values, list):
                        for value in values:
                            if not isinstance(value, float):
                                value = float(value)
                except ValueError as e:
                    raise ValueError('Value was not of type %s' % type)

                type = 'list_of_double'
            add_this_edge_attribute['d'] = type
        else:
            use_this_value, attr_type = self._infer_data_type(values)
            add_this_edge_attribute['v'] = use_this_value
            add_this_edge_attribute['d'] = attr_type

        if add_this_edge_attribute['v'] is not None:
            self.edge_attribute_inventory.append(add_this_edge_attribute)
            self.edge_attribute_map[property_of][name] = True

    def add_opaque_aspect(self, oa_name, oa_list):
        self.opaque_aspect_inventory.append({oa_name: oa_list})

    #===================================
    # methods to add data by fragment
    #===================================
    def _add_network_attributes_from_fragment(self, fragment):
        self.nice_cx.networkAttributes.append(fragment)

    def _add_node_from_fragment(self, fragment):
        node_id = fragment.get('@id')
        if node_id > self.max_node_id:
            self.max_node_id = node_id
        self.nice_cx.nodes[node_id] = fragment

    def _add_edge_from_fragment(self, fragment):
        edge_id = fragment.get('@id')
        if edge_id > self.max_edge_id:
            self.max_edge_id = edge_id
        self.nice_cx.edges[edge_id] = fragment

    def _add_node_attribute_from_fragment(self, fragment):
        if self.nice_cx.nodeAttributes.get(fragment.get('po')) is None:
            self.nice_cx.nodeAttributes[fragment.get('po')] = []

        self.nice_cx.nodeAttributes[fragment.get('po')].append(fragment)

    def _add_edge_attribute_from_fragment(self, fragment):
        if self.nice_cx.edgeAttributes.get(fragment.get('po')) is None:
            self.nice_cx.edgeAttributes[fragment.get('po')] = []

        self.nice_cx.edgeAttributes[fragment.get('po')].append(fragment)

    def _add_citation_from_fragment(self, fragment):
        self.nice_cx.citations[fragment.get('@id')] = fragment

    def _add_supports_from_fragment(self, fragment):
        self.nice_cx.supports[fragment.get('@id')] = fragment

    def _add_edge_supports_from_fragment(self, fragment):
        for po_id in fragment.get('po'):
            self.nice_cx.edgeSupports[po_id] = fragment.get('supports')

    def _add_node_citations_from_fragment(self, fragment):
        for po_id in fragment.get('po'):
            self.nice_cx.nodeCitations[po_id] = fragment.get('citations')

    def _add_edge_citations_from_fragment(self, fragment):
        for po_id in fragment.get('po'):
            self.nice_cx.edgeCitations[po_id] = fragment.get('citations')

    def get_nice_cx(self):
        #==========================
        # ADD CONTEXT
        #==========================
        if isinstance(self.context_inventory, dict):
            self.nice_cx.set_context(self.context_inventory)
        else:
            for c in self.context_inventory:
                self.nice_cx.set_context(c)

        #=============================
        # ASSEMBLE NETWORK ATTRIBUTES
        #=============================
        #{'n': 'name', 'v': network_name, 'd': 'string'}
        for k, v in self.network_attribute_inventory.items():
            self.nice_cx.add_network_attribute(name=v.get('n'),
                                               values=v.get('v'),
                                               type=v.get('d'))

        #==========================
        # ASSEMBLE NODES
        #==========================
        for k, v in self.node_inventory.items():
            self.nice_cx.nodes[v.get('@id')] = v

        #==========================
        # ASSEMBLE NODE ATTRIBUTES
        #==========================
        for a in self.node_attribute_inventory:
            property_of = a.get('po')

            if self.nice_cx.nodeAttributes.get(property_of) is None:
                self.nice_cx.nodeAttributes[property_of] = []

            self.nice_cx.nodeAttributes[property_of].append(a)

        #==========================
        # ASSEMBLE EDGES
        #==========================
        for k, v in self.edge_inventory.items():
            self.nice_cx.edges[k] = v

        #==========================
        # ASSEMBLE EDGE ATTRIBUTES
        #==========================
        for a in self.edge_attribute_inventory:
            property_of = a.get('po')

            if self.nice_cx.edgeAttributes.get(property_of) is None:
                self.nice_cx.edgeAttributes[property_of] = []

            self.nice_cx.edgeAttributes[property_of].append(a)

        #==========================
        # ASSEMBLE OPAQUE ASPECTS
        #==========================
        for oa in self.opaque_aspect_inventory:
            for k, v in oa.items():
                self.nice_cx.add_opaque_aspect(k, v)

        # Fixes issue #60 where there are problems adding
        # new nodes/edges to networks generated
        #
        self.nice_cx.node_int_id_generator = self.max_node_id + 1
        self.nice_cx.edge_int_id_generator = self.max_edge_id + 1

        return self.nice_cx

    def get_frag_from_list_by_key(self, cx, key):
        return_list = []
        for aspect in cx:
            if key in aspect:
                if isinstance(aspect[key], list):
                    for a_item in aspect[key]:
                        return_list.append(a_item)
                else:
                    return_list.append(aspect[key])

        return return_list

    def _infer_data_type(self, val, split_string=False):
        """
        Gets data type of **val** and returns an updated **val** value
        that conforms to the data type inferred

        Okay this is kinda complicated, but this code leverages :python:`isinstance`
        to determine data types


        :param val: Value to infer data type from
        :param split_string: If ``True`` split **val** if it is type :py:func:`str`
                             and it contains ``,`` or ``;``. Order matters if both
                             ``,`` and ``;`` are found **val** is split by ``,``
        :type split_string: bool
        :return: (processed value, CX data type), if **val** is ``None`` then ``(None, None)`` is
                 returned
        :rtype tuple
        """
        if val is None:
            return None, None

        attr_type = 'string'

        if split_string:
            if isinstance(val, str):
                val = val.replace('"', '')
                if ',' in val:
                    val = val.split(',')
                elif ';' in val:
                    val = val.split(';')

        if isinstance(val, float) or isinstance(val, np.float) or isinstance(
                val, np.double):
            if math.isnan(val):
                # do something (skip?)
                val = None
            elif math.isinf(val):
                val = 'INFINITY'
            return val, 'double'
        if isinstance(val, bool):
            # fix for https://github.com/ndexbio/ndex2-client/issues/83
            # a boolean is a sub type of int so bool must be tested first
            return val, 'boolean'
        if isinstance(val, int) or isinstance(val, np.int):
            return val, 'integer'
        if isinstance(val, list):
            # if the list is empty just set data type to list_of_string
            # fix for https://github.com/ndexbio/ndex2-client/issues/90
            attr_type = 'list_of_string'
            if len(val) > 0:
                if isinstance(val[0], float) or isinstance(
                        val[0], np.float) or isinstance(val[0], np.double):
                    attr_type = 'list_of_double'
                elif isinstance(val[0], bool):
                    # fix for https://github.com/ndexbio/ndex2-client/issues/83
                    # a boolean is a sub type of int so bool must be tested first
                    attr_type = 'list_of_boolean'
                elif isinstance(val[0], int) or isinstance(val[0], np.int):
                    attr_type = 'list_of_integer'

        return val, attr_type
Ejemplo n.º 4
0
 def test_add_opaque_aspect_with_dict(self):
     net_cx = NiceCXNetwork()
     data = {'hi': 'blah'}
     net_cx.add_opaque_aspect('hi', data)
     res = net_cx.get_opaque_aspect('hi')
     self.assertEqual([data], res)
Ejemplo n.º 5
0
 def test_add_opaque_aspect_success(self):
     net_cx = NiceCXNetwork()
     data = ['hi']
     net_cx.add_opaque_aspect('hi', data)
     res = net_cx.get_opaque_aspect('hi')
     self.assertEqual(data, res)
Ejemplo n.º 6
0
class NiceCXBuilder(object):
    def __init__(self,
                 cx=None,
                 server=None,
                 username='******',
                 password='******',
                 uuid=None,
                 networkx_G=None,
                 data=None,
                 **attr):
        from ndex2.nice_cx_network import NiceCXNetwork

        self.nice_cx = NiceCXNetwork(user_agent='niceCx Builder')
        self.node_id_lookup = {}
        self.node_id_counter = 0
        self.edge_id_counter = 0

        self.node_inventory = {}
        self.node_attribute_inventory = []
        self.node_attribute_map = {}

        self.edge_inventory = {}
        self.edge_attribute_inventory = []
        self.edge_attribute_map = {}

        self.opaque_aspect_inventory = []

        self.context_inventory = []

        self.network_attribute_inventory = {}

        self.user_base64 = None
        self.username = None
        self.password = None
        if username and password:
            self.username = username
            self.password = password
            if sys.version_info.major == 3:
                encode_string = '%s:%s' % (username, password)
                byte_string = encode_string.encode()
                self.user_base64 = base64.b64encode(
                    byte_string)  #.replace('\n', '')
            else:
                self.user_base64 = base64.encodestring(
                    '%s:%s' % (username, password)).replace('\n', '')

    def set_context(self, context):
        """
        Set the @context information of the network.  This information maps namespace prefixes to their defining URIs

        Example:

            ``set_context({'pmid': 'https://www.ncbi.nlm.nih.gov/pubmed/'})``

        :param context: dict of name, URI pairs
        :type context: dict
        :return: None
        :rtype: none
        """
        if isinstance(context, dict):
            self.context_inventory = context
        elif isinstance(context, list):
            if len(context) > 0:
                self.context_inventory = context[0]

    def set_name(self, network_name):
        """
        Set the network name

        :param network_name: Network name
        :type network_name: string
        :return: None
        :rtype:none
        """

        self.network_attribute_inventory['name'] = {
            'n': 'name',
            'v': network_name,
            'd': 'string'
        }

    def add_network_attribute(self,
                              name=None,
                              values=None,
                              type=None,
                              cx_element=None):
        """
        Add an attribute to the network

        :param name: Name of the attribute
        :type name: str
        :param values:  The value(s) of the attribute
        :type values: One of the allowable CX types.  See `Supported data types`_
        :param type: They type of data supplied in values. Default is string.  See `Supported data types`_
        :type type: str
        :return: None
        :rtype: None
        """

        add_this_network_attribute = {'n': name, 'v': values}
        if type:
            add_this_network_attribute['d'] = type

        self.network_attribute_inventory[name] = add_this_network_attribute

    def add_node(self,
                 name=None,
                 represents=None,
                 id=None,
                 data_type=None,
                 map_node_ids=False):
        """
        Adds a new node with the corresponding name and represents (external id)

        :param node_name: Name of the node
        :type node_name: str
        :param represents: Representation of the node (alternate identifier)
        :type represents: str
        :param id:
        :type id:
        :return: Node ID
        :rtype: int
        """
        if self.node_inventory.get(name) is not None:
            return self.node_inventory.get(name).get('@id')

        if id:
            node_id = id
        else:
            node_id = self.node_id_counter
            self.node_id_counter += 1

        add_this_node = {'@id': node_id, 'n': name}
        if represents:
            add_this_node['r'] = represents
        if data_type:
            add_this_node['d'] = data_type

        self.node_inventory[name] = add_this_node

        if map_node_ids:
            self.node_id_lookup[name] = node_id

        return node_id

    def add_edge(self, source=None, target=None, interaction=None, id=None):
        """
        Adds a new edge in the network by specifying source-interaction-target

        :param source: The source node of this edge, either its id or the node object itself.
        :type source: int, dict (with @id property)
        :param target: The target node of this edge, either its id or the node object itself.
        :type target: int, dict (with @id property)
        :param interaction: The interaction that describes the relationship between the source and target nodes
        :type interaction: str
        :param id: Edge id for this edge.  If none is provided the builder will create one
        :type id: int
        :return: Edge ID
        :rtype: int
        """

        if id is not None:
            edge_id = id
        else:
            edge_id = self.edge_id_counter
            self.edge_id_counter += 1

        add_this_edge = {'@id': edge_id, 's': source, 't': target}
        if interaction:
            add_this_edge['i'] = interaction
        else:
            add_this_edge['i'] = 'interacts-with'

        self.edge_inventory[edge_id] = add_this_edge

        return edge_id

    def add_node_attribute(self, property_of, name, values, type=None):
        """
        Set an attribute of a node, where the node may be specified by its id or passed in as a node dict.

        :param property_of: Node ID to add the attribute to
        :type property_of: int
        :param name: Attribute name
        :type name: str
        :param value: A value or list of values of the attribute
        :type value: list, string, int or float
        :param type: The datatype of the attribute values, defaults is string.  See `Supported data types`_
        :type type: str
        :return: None
        :rtype: None
        """

        if property_of is None:
            raise TypeError('Node value is None')

        if name is None:
            raise TypeError('Property name is None')

        if values is None:
            raise TypeError('Attribute value is None')

        add_this_node_attribute = {'po': property_of, 'n': name, 'v': values}

        if self.node_attribute_map.get(property_of) is None:
            self.node_attribute_map[property_of] = {}
        elif self.node_attribute_map[property_of].get(name) is not None:
            # TODO - Raise warning/exception for duplicate attribute
            return

        if type:
            if type == 'float' or type == 'double':
                type = 'double'
                try:
                    if not isinstance(values, float):
                        add_this_node_attribute['v'] = float(values)
                except ValueError as e:
                    raise ValueError('Value was not of type %s' % type)
            if type == 'list_of_float' or type == 'list_of_double':
                try:
                    if isinstance(values, list):
                        for value in values:
                            if not isinstance(value, float):
                                value = float(value)
                except ValueError as e:
                    raise ValueError('Value was not of type %s' % type)

                type = 'list_of_double'

            add_this_node_attribute['d'] = type
        else:
            use_this_value, attr_type = self._infer_data_type(values)
            add_this_node_attribute['v'] = use_this_value
            add_this_node_attribute['d'] = attr_type

        if add_this_node_attribute['v'] is not None:
            self.node_attribute_inventory.append(add_this_node_attribute)
            self.node_attribute_map[property_of][name] = True

    def add_edge_attribute(self,
                           property_of=None,
                           name=None,
                           values=None,
                           type=None):
        """
        Set the value(s) of attribute of an edge, where the edge may be specified by its id or passed in an object.

        Example:

            ``set_edge_attribute(0, 'weight', 0.5, type='float')``

            or

            ``set_edge_attribute(edge, 'Disease', 'Atherosclerosis')``

        :param property_of: Edge to add the attribute to
        :type property_of: int or edge dict with @id attribute
        :param name: Attribute name
        :type name: str
        :param values: A value or list of values of the attribute
        :type values: list, string, int or float
        :param type: The datatype of the attribute values, defaults to the python datatype of the values.  See `Supported data types`_
        :type type: str
        :return: None
        :rtype: None
        """
        if property_of is None:
            raise TypeError('Edge value is None')

        if name is None:
            raise TypeError('Property name is None')

        if values is None:
            raise TypeError('Attribute value is None')

        add_this_edge_attribute = {'po': property_of, 'n': name, 'v': values}

        if self.edge_attribute_map.get(property_of) is None:
            self.edge_attribute_map[property_of] = {}
        elif self.edge_attribute_map[property_of].get(name) is not None:
            return

        if type:
            if type == 'float' or type == 'double':
                type = 'double'
                try:
                    if not isinstance(values, float):
                        add_this_edge_attribute['v'] = float(values)
                except ValueError as e:
                    raise ValueError('Value was not of type %s' % type)
            if type == 'list_of_float' or type == 'list_of_double':
                try:
                    if isinstance(values, list):
                        for value in values:
                            if not isinstance(value, float):
                                value = float(value)
                except ValueError as e:
                    raise ValueError('Value was not of type %s' % type)

                type = 'list_of_double'
            add_this_edge_attribute['d'] = type
        else:
            use_this_value, attr_type = self._infer_data_type(values)
            add_this_edge_attribute['v'] = use_this_value
            add_this_edge_attribute['d'] = attr_type

        if add_this_edge_attribute['v'] is not None:
            self.edge_attribute_inventory.append(add_this_edge_attribute)
            self.edge_attribute_map[property_of][name] = True

    def add_opaque_aspect(self, oa_name, oa_list):
        self.opaque_aspect_inventory.append({oa_name: oa_list})

    #===================================
    # methods to add data by fragment
    #===================================
    def _add_network_attributes_from_fragment(self, fragment):
        self.nice_cx.networkAttributes.append(fragment)

    def _add_node_from_fragment(self, fragment):
        self.nice_cx.nodes[fragment.get('@id')] = fragment

    def _add_edge_from_fragment(self, fragment):
        self.nice_cx.edges[fragment.get('@id')] = fragment

    def _add_node_attribute_from_fragment(self, fragment):
        if self.nice_cx.nodeAttributes.get(fragment.get('po')) is None:
            self.nice_cx.nodeAttributes[fragment.get('po')] = []

        self.nice_cx.nodeAttributes[fragment.get('po')].append(fragment)

    def _add_edge_attribute_from_fragment(self, fragment):
        if self.nice_cx.edgeAttributes.get(fragment.get('po')) is None:
            self.nice_cx.edgeAttributes[fragment.get('po')] = []

        self.nice_cx.edgeAttributes[fragment.get('po')].append(fragment)

    def _add_citation_from_fragment(self, fragment):
        self.nice_cx.citations[fragment.get('@id')] = fragment

    def _add_supports_from_fragment(self, fragment):
        self.nice_cx.supports[fragment.get('@id')] = fragment

    def _add_edge_supports_from_fragment(self, fragment):
        for po_id in fragment.get('po'):
            self.nice_cx.edgeSupports[po_id] = fragment.get('supports')

    def _add_node_citations_from_fragment(self, fragment):
        for po_id in fragment.get('po'):
            self.nice_cx.nodeCitations[po_id] = fragment.get('citations')

    def _add_edge_citations_from_fragment(self, fragment):
        for po_id in fragment.get('po'):
            self.nice_cx.edgeCitations[po_id] = fragment.get('citations')

    def get_nice_cx(self):
        #==========================
        # ADD CONTEXT
        #==========================
        if isinstance(self.context_inventory, dict):
            self.nice_cx.set_context(self.context_inventory)
        else:
            for c in self.context_inventory:
                self.nice_cx.set_context(c)

        #=============================
        # ASSEMBLE NETWORK ATTRIBUTES
        #=============================
        #{'n': 'name', 'v': network_name, 'd': 'string'}
        for k, v in self.network_attribute_inventory.items():
            self.nice_cx.add_network_attribute(name=v.get('n'),
                                               values=v.get('v'),
                                               type=v.get('d'))

        #==========================
        # ASSEMBLE NODES
        #==========================
        for k, v in self.node_inventory.items():
            self.nice_cx.nodes[v.get('@id')] = v

        #==========================
        # ASSEMBLE NODE ATTRIBUTES
        #==========================
        for a in self.node_attribute_inventory:
            property_of = a.get('po')

            if self.nice_cx.nodeAttributes.get(property_of) is None:
                self.nice_cx.nodeAttributes[property_of] = []

            self.nice_cx.nodeAttributes[property_of].append(a)

        #==========================
        # ASSEMBLE EDGES
        #==========================
        for k, v in self.edge_inventory.items():
            self.nice_cx.edges[k] = v

        #==========================
        # ASSEMBLE EDGE ATTRIBUTES
        #==========================
        for a in self.edge_attribute_inventory:
            property_of = a.get('po')

            if self.nice_cx.edgeAttributes.get(property_of) is None:
                self.nice_cx.edgeAttributes[property_of] = []

            self.nice_cx.edgeAttributes[property_of].append(a)

        #==========================
        # ASSEMBLE OPAQUE ASPECTS
        #==========================
        for oa in self.opaque_aspect_inventory:
            for k, v in oa.items():
                self.nice_cx.add_opaque_aspect(k, v)

        return self.nice_cx

    def get_frag_from_list_by_key(self, cx, key):
        return_list = []
        for aspect in cx:
            if key in aspect:
                if isinstance(aspect[key], list):
                    for a_item in aspect[key]:
                        return_list.append(a_item)
                else:
                    return_list.append(aspect[key])

        return return_list

    def load_aspect(self, aspect_name):
        #with open('Signal1.cx', mode='r') as cx_f:
        with open('network1.cx', mode='r') as cx_f:
            aspect_json = json.loads(cx_f.read())
            for aspect in aspect_json:
                if aspect.get(aspect_name) is not None:
                    return aspect.get(aspect_name)

    def stream_all_aspects(self, uuid):
        return ijson.items(
            urlopen('http://dev2.ndexbio.org/v2/network/' + uuid), 'item')

    def stream_aspect(self, uuid, aspect_name):
        if aspect_name == 'metaData':
            print('http://dev2.ndexbio.org/v2/network/' + uuid + '/aspect')
            md_response = requests.get('http://dev2.ndexbio.org/v2/network/' +
                                       uuid + '/aspect')
            json_respone = md_response.json()
            return json_respone.get('metaData')
        else:
            #password_mgr = HTTPPasswordMgrWithDefaultRealm()

            #top_level_url = 'http://dev2.ndexbio.org'
            #password_mgr.add_password(None, top_level_url, self.username, self.password)
            #handler = HTTPBasicAuthHandler(password_mgr)
            #opener = build_opener(handler)
            #install_opener(opener)

            # Create an OpenerDirector with support for Basic HTTP Authentication...
            #auth_handler = HTTPBasicAuthHandler()
            #auth_handler.add_password(None, 'http://dev2.ndexbio.org', 'scratch', 'scratch')
            #opener = build_opener(auth_handler)
            # ...and install it globally so it can be used with urlopen.
            #install_opener(opener)

            request = Request('http://dev2.ndexbio.org/v2/network/' + uuid +
                              '/aspect/' + aspect_name)
            base64string = base64.b64encode('%s:%s' % ('scratch', 'scratch'))
            request.add_header("Authorization", "Basic %s" % base64string)
            #result = urllib2.urlopen(request)

            urlopen_result = None
            try:
                urlopen_result = urlopen(
                    request
                )  #'http://dev2.ndexbio.org/v2/network/' + uuid + '/aspect/' + aspect_name)
            except HTTPError as e:
                print(e.code)
                return []
            except URLError as e:
                print('Other error')
                print('URL Error %s' % e.message())
                return []

            return ijson.items(urlopen_result, 'item')

    def stream_aspect_raw(self, uuid, aspect_name):
        return ijson.parse(
            urlopen('http://dev2.ndexbio.org/v2/network/' + uuid + '/aspect/' +
                    aspect_name))

    def _infer_data_type(self, val, split_string=False):
        if val is None:
            return None, None

        attr_type = 'string'

        if split_string:
            if isinstance(val, str):
                val = val.replace('"', '')
                if ',' in val:
                    val = val.split(',')
                elif ';' in val:
                    val = val.split(';')

        processed_value = val

        if isinstance(val, float) or isinstance(val, np.float) or isinstance(
                val, np.double):
            if math.isnan(val):
                # do something (skip?)
                processed_value = None
            elif math.isinf(val):
                processed_value = 'INFINITY'
            attr_type = 'double'  # CX spec dropped support for float and instead uses double precision
        elif isinstance(val, int) or isinstance(val, np.int):
            attr_type = 'integer'
        elif isinstance(val, list):
            if len(val) > 0:
                if isinstance(val[0], float) or isinstance(
                        val[0], np.float) or isinstance(val[0], np.double):
                    attr_type = 'list_of_double'
                elif isinstance(val[0], int) or isinstance(val[0], np.int):
                    attr_type = 'list_of_integer'
                else:
                    attr_type = 'list_of_string'

        return processed_value, attr_type