Source code for linchemin.cgu.convert
from abc import ABC, abstractmethod
from typing import Union
from linchemin.cgu.syngraph import (
BipartiteSynGraph,
MonopartiteMolSynGraph,
MonopartiteReacSynGraph,
SynGraph,
)
from linchemin.cgu.syngraph_operations import extract_reactions_from_syngraph
"""
Module containing all the functions to convert from and into different SynGraph data models:
-bipartite molecules and reactions
-monopartite molecules
-monopartite reactions
"""
# Abstract strategy class
class Converter(ABC):
"""Abstract class for data model converters"""
input_data_model: Union[
BipartiteSynGraph, MonopartiteMolSynGraph, MonopartiteReacSynGraph
]
output_data_model: Union[
BipartiteSynGraph, MonopartiteMolSynGraph, MonopartiteReacSynGraph
]
out_datamodels = {
"bipartite": BipartiteSynGraph,
"monopartite_reactions": MonopartiteReacSynGraph,
"monopartite_molecules": MonopartiteMolSynGraph,
}
@abstractmethod
def convert(
self,
graph: Union[
BipartiteSynGraph, MonopartiteMolSynGraph, MonopartiteReacSynGraph
],
):
pass
# Concrete strategy classes
class BipartiteToMonopartiteReactions(Converter):
"""Converter subclass to convert a bipartite SynGraph in a monopartite reactions SynGraph"""
input_data_model = BipartiteSynGraph
output_data_model = MonopartiteReacSynGraph
def convert(self, graph: BipartiteSynGraph):
"""To build a MonopartiteSynGraph with only ReactionStep nodes from a bipartite SynGraph."""
out_reaction_list = extract_reactions_from_syngraph(graph)
in_reaction_list = [
{"query_id": d["query_id"], "output_string": d["input_string"]}
for d in out_reaction_list
]
mp_graph = MonopartiteReacSynGraph(in_reaction_list)
mp_graph.name = graph.name
return mp_graph
class BipartiteToMonopartiteMolecules(Converter):
"""Converter subclass to convert a bipartite SynGraph in a monopartite molecules SynGraph"""
input_data_model = BipartiteSynGraph
output_data_model = MonopartiteMolSynGraph
def convert(self, graph: BipartiteSynGraph):
"""To build a MonopartiteSynGraph with only Molecules nodes from a bipartite SynGraph."""
out_reaction_list = extract_reactions_from_syngraph(graph)
in_reaction_list = [
{"query_id": d["query_id"], "output_string": d["input_string"]}
for d in out_reaction_list
]
mp_graph = MonopartiteMolSynGraph(in_reaction_list)
mp_graph.name = graph.name
return mp_graph
class MonopartiteMoleculesToMonopartiteReactions(Converter):
"""Converter subclass to convert a monopartite reactions SynGraph in a monopartite molecules SynGraph"""
input_data_model = MonopartiteMolSynGraph
output_data_model = MonopartiteReacSynGraph
def convert(self, graph: MonopartiteMolSynGraph) -> MonopartiteReacSynGraph:
out_reaction_list = extract_reactions_from_syngraph(graph)
in_reaction_list = [
{"query_id": d["query_id"], "output_string": d["input_string"]}
for d in out_reaction_list
]
mp_graph = MonopartiteReacSynGraph(in_reaction_list)
mp_graph.name = graph.name
return mp_graph
class MonopartiteMoleculesToBiparite(Converter):
"""Converter subclass to convert a monopartite reactions SynGraph in a bipartite SynGraph"""
input_data_model = MonopartiteMolSynGraph
output_data_model = BipartiteSynGraph
def convert(self, graph: MonopartiteMolSynGraph) -> BipartiteSynGraph:
out_reaction_list = extract_reactions_from_syngraph(graph)
in_reaction_list = [
{"query_id": d["query_id"], "output_string": d["input_string"]}
for d in out_reaction_list
]
bp_graph = BipartiteSynGraph(in_reaction_list)
bp_graph.name = graph.name
return bp_graph
class MonopartiteReactionsToMonopartiteMolecules(Converter):
"""Converter subclass to convert a monopartite reactions SynGraph in a monopartite molecules SynGraph"""
input_data_model = MonopartiteReacSynGraph
output_data_model = MonopartiteMolSynGraph
def convert(self, graph: MonopartiteReacSynGraph) -> MonopartiteMolSynGraph:
out_reaction_list = extract_reactions_from_syngraph(graph)
in_reaction_list = [
{"query_id": d["query_id"], "output_string": d["input_string"]}
for d in out_reaction_list
]
bp_graph = MonopartiteMolSynGraph(in_reaction_list)
bp_graph.name = graph.name
return bp_graph
class MonopartiteReactionsToBipartite(Converter):
"""Converter subclass to convert a monopartite reactions SynGraph in a bipartite SynGraph"""
input_data_model = MonopartiteReacSynGraph
output_data_model = BipartiteSynGraph
def convert(self, graph: MonopartiteReacSynGraph) -> BipartiteSynGraph:
out_reaction_list = extract_reactions_from_syngraph(graph)
in_reaction_list = [
{"query_id": d["query_id"], "output_string": d["input_string"]}
for d in out_reaction_list
]
bp_graph = BipartiteSynGraph(in_reaction_list)
bp_graph.name = graph.name
return bp_graph
# Context class
class Conversion:
def __init__(self, input_data_model: str, output_data_model: str):
c = next(
subclass
for subclass in Converter.__subclasses__()
if subclass.input_data_model == input_data_model
and subclass.output_data_model == output_data_model
)
self.converter = c()
def apply_conversion(
self,
graph: Union[
MonopartiteReacSynGraph, MonopartiteMolSynGraph, BipartiteSynGraph
],
):
return self.converter.convert(graph)
[docs]
def converter(
graph: Union[MonopartiteReacSynGraph, MonopartiteMolSynGraph, BipartiteSynGraph],
out_data_model: str,
) -> Union[MonopartiteReacSynGraph, MonopartiteMolSynGraph, BipartiteSynGraph]:
"""
To convert a SynGraph object in other types of SynGraph
Parameters:
------------
graph: SynGraph
The input graph as instance of one of the available SynGraph subclasses
out_data_model: str
The desired output data model.
Returns:
---------
converted graph: Union[MonopartiteReacSynGraph, BipartiteSynGraph, MonopartiteMolSynGraph]
The converted graph
Raises:
--------
TypeError: if the input graph is of the wrong type
KeyError: if the selected output data model is not available
Example:
--------
>>> mp_syngraph = converter(bp_syngraph, 'monopartite_molecules')
"""
if not isinstance(graph, SynGraph):
raise TypeError("Invalid input type. Only SynGraph objects con be converted.")
if out_data_model not in Converter.out_datamodels:
raise KeyError(
f"Invalid output data model. Available data models are: {Converter.out_datamodels.keys()}"
)
if type(graph) == Converter.out_datamodels[out_data_model]:
# print('The input SynGraph is already in the required data model')
return graph
in_data_model = type(graph)
out_dm = Converter.out_datamodels[out_data_model]
c = Conversion(in_data_model, out_dm)
return c.apply_conversion(graph)