From 4e82022dc803e1a0a8fdbf63615d575ea4a29af4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joan=20H=C3=A9risson?= Date: Wed, 15 Apr 2026 09:58:37 +0200 Subject: [PATCH 1/5] doc(README.md): update --- README.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c0cbb78..b4a3603 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ conda install -c conda-forge rplibs softwareupdate --install-rosetta --agree-to-license ``` -### 2. Install rpLibs +### 2. Install ```bash CONDA_SUBDIR=osx-64 conda install -c conda-forge rplibs @@ -68,11 +68,16 @@ CONDA_SUBDIR=osx-64 mamba install -c conda-forge rplibs conda config --env --set subdir osx-64 ``` -### 5. Verify installation +### 4. Verify installation ```bash python -c "import rplibs; print('rplibs installed successfully')" -python -c "import cobra; print(cobra.__version__)" +``` + +### 5. (Optional) Dev installation + +```bash +CONDA_SUBDIR=osx-64 conda env create -f environment.yaml ``` --- From c4ddf2fa82c496e83249512d223f09c2d57c0757 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joan=20H=C3=A9risson?= Date: Fri, 29 May 2026 15:35:16 +0200 Subject: [PATCH 2/5] build(environment.yaml): add dep + pin ver --- environment.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/environment.yaml b/environment.yaml index 9cbaf91..702340a 100644 --- a/environment.yaml +++ b/environment.yaml @@ -8,6 +8,7 @@ dependencies: - networkx>=2.5 - filetype - brs_utils>=1.26.0 - - chemlite + - chemlite>=2.8.0 - rr_cache - cobra + - libsbml From 1ac42bf4a9542910d7892270ddde9b83667b2dd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joan=20H=C3=A9risson?= Date: Fri, 29 May 2026 15:37:09 +0200 Subject: [PATCH 3/5] chore(rplibs/rpPathway.py): rm target_id --- rplibs/rpPathway.py | 77 ++++++++++++++++++++++---------------------- rplibs/rpReaction.py | 33 ++++++++++--------- 2 files changed, 55 insertions(+), 55 deletions(-) diff --git a/rplibs/rpPathway.py b/rplibs/rpPathway.py index a656138..24e955b 100644 --- a/rplibs/rpPathway.py +++ b/rplibs/rpPathway.py @@ -74,7 +74,6 @@ def __init__( ) rpObject.__init__(self, logger) self.__species_groups = {} - self.set_target_id(None) self.__unit_def = {} self.__compartments = {} self.add_compartment( @@ -206,9 +205,9 @@ def get_rxn_target(self) -> rpReaction: the target compound of the pathway.""" return self.get_reaction(self.get_target_rxn_id()) - def get_target_id(self) -> str: - """Get the ID of the pathway target compound.""" - return self.__target_id + # def get_target_id(self) -> str: + # """Get the ID of the pathway target compound.""" + # return self.__target_id def get_target(self) -> rpCompound: """Get the object of the pathway target compound.""" @@ -462,18 +461,18 @@ def set_sink_species(self, species: List[str]) -> None: self.__build_intermediate_species() # self.__sink = deepcopy(sink) - def set_target_id(self, id: str) -> None: - """Set the ID of the pathway target. - After that, 'intermediate' species group is rebuilt. + # def set_target_id(self, id: str) -> None: + # """Set the ID of the pathway target. + # After that, 'intermediate' species group is rebuilt. - Parameters - ---------- - id: str - ID of the species to set as the pathway target. - """ - self.__target_id = id - # (re-)build intermediate species group - self.__build_intermediate_species() + # Parameters + # ---------- + # id: str + # ID of the species to set as the pathway target. + # """ + # self.__target_id = id + # # (re-)build intermediate species group + # self.__build_intermediate_species() def add_unit_def( self, id: str, kind: int, exp: int, scale: int, mult: float @@ -632,9 +631,9 @@ def __import_rpSBML( rxn_infos["fbc_units"] = self.get_parameter_units( rxn_infos["fbc_lower_value"] ) - reaction, target_id = rpReaction.build(rxn_id, rxn_infos, logger) + reaction = rpReaction.build(rxn_id, rxn_infos, logger) # Add the reaction to the pathway - self.add_reaction(rxn=reaction, target_id=target_id) + self.add_reaction(rxn=reaction) ## GROUPS for group in rpsbml.getPlugin("groups").getListOfGroups(): @@ -801,7 +800,7 @@ def to_rpSBML(self, cache: rrCache = None, local_cache: dict = {}) -> rpSBML: rpsbml.create_enriched_group( group_id="rp_pathway", members=self.get_reactions_ids(), - infos={**rpObject._to_dict(self), "global_score": self.get_global_score()}, + infos={**rpObject._to_dict(self), "global_score": self.get_global_score(), "target_id": self.get_target_id()}, ) for group_id, group_members in self.get_species_groups().items(): _members = [local_cache.get(spe_id, spe_id) for spe_id in group_members] @@ -828,27 +827,27 @@ def from_rpSBML(rpsbml: rpSBML) -> "rpPathway": pathway.__import_rpSBML(rpsbml) return pathway - def add_reaction( - self, rxn: rpReaction, rxn_id: str = None, target_id: str = None - ) -> None: - """ - Add a reaction to the pathway. - - Parameters - ---------- - rxn: rpReaction - Reaction object to add - rxn_id: str, optional - ID of the reaction within the pathway - target_id: str, optional - ID of the compound if it is the pathway target - """ - - super().add_reaction(rxn, rxn_id) - - # TARGET - if target_id is not None: - self.set_target_id(target_id) + # def add_reaction( + # self, rxn: rpReaction, rxn_id: str = None, target_id: str = None + # ) -> None: + # """ + # Add a reaction to the pathway. + + # Parameters + # ---------- + # rxn: rpReaction + # Reaction object to add + # rxn_id: str, optional + # ID of the reaction within the pathway + # target_id: str, optional + # ID of the compound if it is the pathway target + # """ + + # super().add_reaction(rxn, rxn_id) + + # # TARGET + # if target_id is not None: + # self.set_target_id(target_id) ## MISC def rename_compound(self, id: str, new_id: str) -> None: diff --git a/rplibs/rpReaction.py b/rplibs/rpReaction.py index e4cb880..2edb811 100644 --- a/rplibs/rpReaction.py +++ b/rplibs/rpReaction.py @@ -79,22 +79,23 @@ def build( ) # Add additional infos write_to(infos["brsynth"], reaction) - # Detects if the current reaction produces the target - target_id = [ - spe_id for spe_id in reaction.get_products_ids() if "TARGET" in spe_id - ] - if target_id != []: - target_id = target_id[0] - else: - # If not, detects if the current reaction consumes the target - target_id = [ - spe_id for spe_id in reaction.get_reactants_ids() if "TARGET" in spe_id - ] - if target_id != []: - target_id = target_id[0] - else: - target_id = None - return reaction, target_id + # # Detects if the current reaction produces the target + # target_id = [ + # spe_id for spe_id in reaction.get_products_ids() if "TARGET" in spe_id + # ] + # if target_id != []: + # target_id = target_id[0] + # else: + # # If not, detects if the current reaction consumes the target + # target_id = [ + # spe_id for spe_id in reaction.get_reactants_ids() if "TARGET" in spe_id + # ] + # if target_id != []: + # target_id = target_id[0] + # else: + # target_id = None + # return reaction, target_id + return reaction def __init__( self, From 51b44da1b3df59ce267a523095eefdba1612905d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joan=20H=C3=A9risson?= Date: Fri, 29 May 2026 15:37:57 +0200 Subject: [PATCH 4/5] test: add target --- tests/data/lycopene.sbml | 1 + tests/test_rpPathway.py | 50 ++++++++++++++++++++++++++++------------ 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/tests/data/lycopene.sbml b/tests/data/lycopene.sbml index 539ecd1..67eb85b 100644 --- a/tests/data/lycopene.sbml +++ b/tests/data/lycopene.sbml @@ -546,6 +546,7 @@ + diff --git a/tests/test_rpPathway.py b/tests/test_rpPathway.py index 7a7bac1..0f73bd2 100644 --- a/tests/test_rpPathway.py +++ b/tests/test_rpPathway.py @@ -20,7 +20,10 @@ class Test_rpPathway(Main_rplibs): def setUp(self): self.target = rpCompound( id="TARGET_0000000001", - smiles="[H]OC(=O)C([H])=C([H])C([H])=C([H])C(=O)O[H]", + smiles="[H]C(=C([H])C([H])=C(C([H])=C([H])C([H])=C(C([H])=C([H])C([H])=C(C([H])([H])[H])C([H])([H])C([H])([H])C([H])=C(C([H])([H])[H])C([H])([H])[H])C([H])([H])[H])C([H])([H])[H])C([H])=C(C([H])=C([H])C([H])=C(C([H])=C([H])C([H])=C(C([H])([H])[H])C([H])([H])C([H])([H])C([H])=C(C([H])([H])[H])C([H])([H])[H])C([H])([H])[H])C([H])([H])[H]", + inchi='InChI=1S/C40H56/c1-33(2)19-13-23-37(7)27-17-31-39(9)29-15-25-35(5)21-11-12-22-36(6)26-16-30-40(10)32-18-28-38(8)24-14-20-34(3)4/h11-12,15-22,25-32H,13-14,23-24H2,1-10H3', + inchikey='OAIJSZIZWZSQBC-UHFFFAOYSA-N', + formula='' ) # species = { # # "TARGET_0000000001": rpCompound( @@ -197,7 +200,7 @@ def setUp(self): ], } self.pathway = rpPathway( - id=self.id, + id=self.id ) self.pathway.set_parameters(self.parameters) self.pathway.set_unit_defs(self.unit_def) @@ -206,7 +209,8 @@ def setUp(self): self.rxn.set_tmpl_rxn_ids(self.tmpl_rxn_ids) self.rxn.set_idx_in_path(self.idx_in_path) self.rxn.set_rule_score(self.rule_score) - self.pathway.add_reaction(rxn=self.rxn, target_id=self.target.get_id()) + self.pathway.add_reaction(rxn=self.rxn) + self.pathway.set_target_id(self.target.get_id()) for rxn in self.reactions[1:]: self.pathway.add_reaction(rxn) self.sink = ["MNXM23", "MNXM6", "MNXM13"] @@ -215,6 +219,8 @@ def setUp(self): self.pathway.add_thermo_info(key, value) self.pathway.set_fba_fraction(self.fba) + self.rpsbml_lycopene = rpPathway(infile=self.rpsbml_lycopene_path) + ## READ METHODS def test__to_dict(self): self.assertDictEqual( @@ -302,7 +308,20 @@ def test_get_rxn_target(self): self.assertEqual(self.pathway.get_rxn_target(), self.rxn) def test_get_target(self): - self.assertEqual(self.pathway.get_target(), self.target) + # Compare ID, name, smiles, inchi, inchikey, formula, but not annotations, to avoid issues with the cache + self.__compare_compound(self.pathway.get_target(), self.target) + + def __compare_compound(self, cmpd1: rpCompound, reference: rpCompound): + self.assertEqual(cmpd1.get_id(), reference.get_id()) + self.assertEqual(cmpd1.get_name(), reference.get_name()) + self.assertEqual(cmpd1.get_smiles(), reference.get_smiles()) + self.assertEqual(cmpd1.get_inchi(), reference.get_inchi()) + self.assertEqual(cmpd1.get_inchikey(), reference.get_inchikey()) + self.assertEqual(cmpd1.get_formula(), reference.get_formula()) + + def test_read_target(self): + target = rpPathway(infile=self.rpsbml_lycopene_path).get_target() + self.__compare_compound(target, self.target) def test_get_parameters(self): self.assertDictEqual(self.pathway.get_parameters(), self.parameters) @@ -317,21 +336,21 @@ def test_get_fba(self): def test_get_thermo(self): self.assertDictEqual(self.pathway.get_thermo(), self.thermo) - def test_rpSBML_rpsbml(self): + def test_rpPathway2rpSBML2rpPathway(self): self.assertEqual( self.pathway, rpPathway.from_rpSBML(rpsbml=self.pathway.to_rpSBML()) ) - def test_rpSBML_file(self): - with NamedTemporaryFile(delete=False) as tempf: - tempf.close() - self.assertEqual( - self.pathway, rpPathway.from_rpSBML(self.pathway.to_rpSBML()) - ) - tempf.close() - remove(tempf.name) + # def test_rpSBML_file(self): + # with NamedTemporaryFile(delete=False) as tempf: + # tempf.close() + # self.assertEqual( + # self.pathway, rpPathway.from_rpSBML(self.pathway.to_rpSBML()) + # ) + # tempf.close() + # remove(tempf.name) - def test_rpSBML_file_rpsbml(self): + def test_rpPathway2SBML2rpPathway(self): with NamedTemporaryFile(delete=False) as tempf: self.pathway.to_rpSBML().write_to_file(tempf.name) self.assertEqual(self.pathway, rpPathway(infile=tempf.name)) @@ -380,7 +399,8 @@ def test_add_parameter(self): def test_eq(self): pathway = rpPathway(id="test_pathway") - pathway.add_reaction(rxn=self.rxn, target_id="TARGET_0000000001") + pathway.add_reaction(rxn=self.rxn) + pathway.set_target_id("TARGET_0000000001") for rxn in self.reactions[1:]: pathway.add_reaction(rxn) self.assertEqual(self.pathway, pathway) From 93d37eeb77f56fda13b8a27ca36df6ae70c12c82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joan=20H=C3=A9risson?= Date: Fri, 29 May 2026 15:40:23 +0200 Subject: [PATCH 5/5] style: black job --- rplibs/rpPathway.py | 6 +++++- tests/test_rpPathway.py | 10 ++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/rplibs/rpPathway.py b/rplibs/rpPathway.py index 24e955b..ba37809 100644 --- a/rplibs/rpPathway.py +++ b/rplibs/rpPathway.py @@ -800,7 +800,11 @@ def to_rpSBML(self, cache: rrCache = None, local_cache: dict = {}) -> rpSBML: rpsbml.create_enriched_group( group_id="rp_pathway", members=self.get_reactions_ids(), - infos={**rpObject._to_dict(self), "global_score": self.get_global_score(), "target_id": self.get_target_id()}, + infos={ + **rpObject._to_dict(self), + "global_score": self.get_global_score(), + "target_id": self.get_target_id(), + }, ) for group_id, group_members in self.get_species_groups().items(): _members = [local_cache.get(spe_id, spe_id) for spe_id in group_members] diff --git a/tests/test_rpPathway.py b/tests/test_rpPathway.py index 0f73bd2..552fb02 100644 --- a/tests/test_rpPathway.py +++ b/tests/test_rpPathway.py @@ -21,9 +21,9 @@ def setUp(self): self.target = rpCompound( id="TARGET_0000000001", smiles="[H]C(=C([H])C([H])=C(C([H])=C([H])C([H])=C(C([H])=C([H])C([H])=C(C([H])([H])[H])C([H])([H])C([H])([H])C([H])=C(C([H])([H])[H])C([H])([H])[H])C([H])([H])[H])C([H])([H])[H])C([H])=C(C([H])=C([H])C([H])=C(C([H])=C([H])C([H])=C(C([H])([H])[H])C([H])([H])C([H])([H])C([H])=C(C([H])([H])[H])C([H])([H])[H])C([H])([H])[H])C([H])([H])[H]", - inchi='InChI=1S/C40H56/c1-33(2)19-13-23-37(7)27-17-31-39(9)29-15-25-35(5)21-11-12-22-36(6)26-16-30-40(10)32-18-28-38(8)24-14-20-34(3)4/h11-12,15-22,25-32H,13-14,23-24H2,1-10H3', - inchikey='OAIJSZIZWZSQBC-UHFFFAOYSA-N', - formula='' + inchi="InChI=1S/C40H56/c1-33(2)19-13-23-37(7)27-17-31-39(9)29-15-25-35(5)21-11-12-22-36(6)26-16-30-40(10)32-18-28-38(8)24-14-20-34(3)4/h11-12,15-22,25-32H,13-14,23-24H2,1-10H3", + inchikey="OAIJSZIZWZSQBC-UHFFFAOYSA-N", + formula="", ) # species = { # # "TARGET_0000000001": rpCompound( @@ -199,9 +199,7 @@ def setUp(self): {"kind": 13, "exponent": -1, "scale": 1, "multiplier": 1.0}, ], } - self.pathway = rpPathway( - id=self.id - ) + self.pathway = rpPathway(id=self.id) self.pathway.set_parameters(self.parameters) self.pathway.set_unit_defs(self.unit_def) self.rxn.set_rp2_transfo_id(self.rp2_transfo_id)