def test_design_removals(): with FakeProjectContext() as ctx: # Design with removal of reactions, metabolites, genes project = GSMProject(ctx.path) mdl = project.load_model() rx = mdl.reactions.get_by_id('TPI') rx.remove_from_model() gx = mdl.genes.get_by_id("b3916") gx.name = 'ffoods' mx = mdl.metabolites.get_by_id('h2o_c') mx.remove_from_model() des = project.save_design(mdl, 'test', 'test', description='test', overwrite=True) des._genes.append( dict(id='ffooo', name='', functional=True, notes=None, annotation={})) des._removed_metabolites.append('ttttesssst') tp = des.load() assert rx.id not in tp.reactions assert mx.id not in tp.metabolites
def test_existing_project(): """ Force project exists exception to be thrown """ with FakeProjectContext() as ctx: with pytest.raises(ProjectConfigurationError): project_creator(ctx.path, [])
def test_conditions(): with FakeProjectContext() as fp: # add some growth conditions fp.add_fake_conditions() mdl = fp.project.model load_medium(mdl, dict()) fp.project.save_conditions(mdl, "bad", apply_to=fp.project.config.default_model, observe_growth=False) # Shouldn't allow conditions that don't grow without being formally specified with pytest.raises(Infeasible): fp.project.save_conditions( mdl, "very bad", apply_to=fp.project.config.default_model) assert (len( fp.project.get_conditions(update=True)['growth_conditions']) == 2) # run the default test tester = fp.project.project_tester() tester.collect_tests() assert (len(tester.default_tests) == 3) tester.run_all() # Test the cli interface runner = CliRunner() result = runner.invoke(gsmodutils.cli.test, ['--project_path', fp.path, '--verbose']) assert result.exit_code == 0
def test_json_tests(): """ Test the execution of json tests""" with FakeProjectContext() as fp: # Create a fake json file with tests in it jtest = dict( test_1=dict(models=[], conditions=[], designs=[], reaction_fluxes=dict( BIOMASS_Ec_iAF1260_core_59p81M=[0.72, 0.74]), required_reactions=["DHQS"], description='TEST JSON TEST')) project = GSMProject(fp.path) tpath = os.path.join(project.tests_dir, 'test_x.json') # write to project path with open(tpath, "w+") as ff: json.dump(jtest, ff) jtest = dict( test_1=dict(conditions=[], designs=[], reaction_fluxes=dict( BIOMASS_Ec_iAF1260_core_59p81M=[0.72, 0.74]), required_reactions=["DHQS"], description='TEST JSON TEST')) project = GSMProject(fp.path) tpath = os.path.join(project.tests_dir, 'test_invalid.json') # write to project path with open(tpath, "w+") as ff: json.dump(jtest, ff) tpath = os.path.join(project.tests_dir, 'test_load_error.json') with open(tpath, 'w+') as tt: tt.write('not json\n') # run test functions tester = project.project_tester() tester.collect_tests() assert len(tester.json_tests) == 1 tester.run_all() assert len(tester.load_errors) == 1 assert len(tester.invalid_tests) == 1 runner = CliRunner() result = runner.invoke(gsmodutils.cli.test, ['--project_path', fp.path, '--verbose']) assert result.exit_code == 0 result = runner.invoke(gsmodutils.cli.test, [ '--project_path', fp.path, '--verbose', '--test_id', 'test_x.json' ]) assert result.exit_code == 0
def test_existing_conditions_file(): """ Test a project where there is no project file but an existing growth conditions configuration """ with FakeProjectContext() as ctx: os.remove(os.path.join(ctx.path, default_project_file)) with pytest.raises(ProjectConfigurationError): project_creator(ctx.path, [])
def test_save_infeasible_design(): with FakeProjectContext() as fp: model = fp.project.model with pytest.raises(Infeasible): for m in model.medium: model.reactions.get_by_id(m).lower_bound = 0 fp.project.save_design(model, 'foo', 'test')
def test_load_conditions(): with FakeProjectContext() as ctx: project = GSMProject(ctx.path) model = project.model # Growth on xylose instead of glucose model.reactions.EX_xyl__D_e.lower_bound = -8.00 model.reactions.EX_glc__D_e.lower_bound = 0.0 model.reactions.EX_h_e.objective_coefficient = 1.0 project.save_conditions(model, 'xylose_growth', carbon_source="EX_xyl__D_e") # The model should be reloaded so it isn't the same reference del model new_model = project.load_conditions('xylose_growth') assert new_model.reactions.EX_xyl__D_e.lower_bound == -8.00 assert new_model.reactions.EX_xyl__D_e.upper_bound == -8.00 assert new_model.reactions.EX_glc__D_e.lower_bound == 0.0 # Test model objective assert new_model.reactions.EX_h_e.objective_coefficient == 1.0 assert new_model.reactions.BIOMASS_Ec_iAF1260_core_59p81M.objective_coefficient == 1.0 del new_model model = project.model # test using a copy of the model too_model = project.load_conditions('xylose_growth', model=model, copy=True) model.reactions.EX_xyl__D_e.lower_bound = 0.00 assert model.reactions.EX_xyl__D_e.lower_bound != too_model.reactions.EX_xyl__D_e.lower_bound # Model growth when it shouldn't with pytest.raises(AssertionError): project.save_conditions(too_model, 'xylose_growth2', carbon_source="EX_xyl__D_e", observe_growth=False) # Bad "apply_to" model with pytest.raises(KeyError): project.save_conditions(too_model, 'xylose_growth3', carbon_source="EX_xyl__D_e", apply_to=["FOO"]) # Bad growth target with pytest.raises(KeyError): project.save_conditions(too_model, 'xylose_growth3', carbon_source="EX_foo")
def test_stoich_st(): convert_stoich({"a": -1, "b": -1, "c": 1}) with pytest.raises(TypeError): equal_stoich({}, {}) with FakeProjectContext() as ctx: model = ctx.project.model assert equal_stoich(model.reactions[20], model.reactions[20]) assert not equal_stoich(model.reactions[20], model.reactions[30])
def test_biomass_debug(): with pytest.raises(TypeError): biomass_debug(None, 'foo') with FakeProjectContext() as ctx: # Valid model model = ctx.project.model # Remove way of producing non_products = biomass_debug( model, model.reactions.BIOMASS_Ec_iAF1260_core_59p81M) assert len(non_products) == 0
def test_project_update(): with FakeProjectContext() as ctx: project = GSMProject(ctx.path) assert len(project.models) project.update() with pytest.raises(ProjectNotFound): project._project_path = 'NOT_REAL_PATH' project.update() # Test non existent designs with pytest.raises(DesignNotFoundError): project.get_design("fooooo")
def test_info(): with FakeProjectContext() as ctx: ctx.add_fake_designs() ctx.add_fake_conditions() runner = CliRunner() result = runner.invoke(gsmodutils.cli.info, ['--project_path', ctx.path]) assert result.exit_code == 0 # Test bad project path fail result = runner.invoke(gsmodutils.cli.info, []) assert result.exit_code == -1 # Pointless test for code coverage runner.invoke(gsmodutils.cli.cli)
def test_save_design(): with FakeProjectContext() as ctx: ctx.add_fake_conditions() ctx.add_fake_designs() project = GSMProject(ctx.path) design = project.get_design("mevalonate_cbb") mdl = GSModutilsModel(project, design=design) mdl.save_model() # Can't save py designs that have been modified with pytest.raises(NotImplementedError): design = project.get_design("fake_testpy") mdl = GSModutilsModel(project, design=design) mdl.save_model()
def test_copy(): with FakeProjectContext() as ctx: project = GSMProject(ctx.path) assert project.project_path == ctx.path model = GSModutilsModel(project) copied = model.copy() assert model is not copied for met in copied.metabolites: assert met is not model.metabolites.get_by_id(met.id) assert met.model is not model for gene in copied.genes: assert gene is not model.genes.get_by_id(gene.id) assert gene.model is not model
def test_addmodel(): with FakeProjectContext() as ctx: runner = CliRunner() result = runner.invoke(gsmodutils.cli.addmodel, [_CORE_MODEL_PATH, '--project_path', ctx.path]) assert result.exit_code == 0 project = GSMProject(ctx.path) assert "e_coli_core.json" in project.config.models # Should fail when model already exists result = runner.invoke(gsmodutils.cli.addmodel, [_CORE_MODEL_PATH, '--project_path', ctx.path]) assert result.exit_code == -1
def test_create_project(): """ Create a test project with an example e coli model """ # When writing tests use a different folder for multiprocess! with FakeProjectContext() as ctx: # Make sure all files exist assert os.path.exists(ctx.path) assert os.path.exists(os.path.join(ctx.path, default_project_file)) assert os.path.exists( os.path.join(ctx.path, default_model_conditionsfp)) # check project loads GSMProject(ctx.path)
def test_existing_dir(): """ Tests existing directory and folder assumes test_create_project works """ with FakeProjectContext() as ctx: # create an existing project and delete the config files os.remove(os.path.join(ctx.path, default_project_file)) os.remove(os.path.join(ctx.path, default_model_conditionsfp)) project_creator(ctx.path, []) assert os.path.exists(os.path.join(ctx.path, default_project_file)) assert os.path.exists( os.path.join(ctx.path, default_model_conditionsfp))
def test_model_tests(): code_str = """ # Look our tests are python 2 compatible! # p.s. if you're reading this you're such a nerd from __future__ import print_function from gsmodutils.test.utils import ModelTestSelector @ModelTestSelector(designs=["mevalonate_cbb"]) def test_funcdes(model, project, log): log.assertion(False, "Works", "Does not work", "Test1") @ModelTestSelector(conditions=["xyl_src"]) def test_func(model, project, log): log.assertion(True, "Works", "Does not work", "Test2") """ with FakeProjectContext(use_second_model=True) as ctx: ctx.add_fake_conditions() ctx.add_fake_designs() test_codep = 'test_code.py' tfp = os.path.join(ctx.project.tests_dir, test_codep) with open(tfp, "w+") as codef: codef.write(code_str) # Test a design design = ctx.project.load_design("mevalonate_cbb") testsdes = design.run_tests() assert len(testsdes) == 2 assert not testsdes[ "test_code.py::test_funcdes::iAF1260.json::mevalonate_cbb"].log.is_success # Test a model model = ctx.project.load_model() tests = model.run_tests() assert len(tests) == 3 assert tests["model::iAF1260.json"].log.is_success assert tests["model::iAF1260.json::conditions::xyl_src"].log.is_success assert tests[ "test_code.py::test_func::iAF1260.json::xyl_src"].log.is_success # Test a second model model2 = ctx.project.load_model('e_coli_core.json') tests2 = model2.run_tests(display_progress=False) assert len(tests2) == 1 assert tests2["model::e_coli_core.json"].log.is_success
def test_old_conditions(): """ Test to see if old conditions (without setting objective function) breaks :return: """ with FakeProjectContext() as ctx: project = GSMProject(ctx.path) model = project.model model.reactions.EX_xyl__D_e.lower_bound = -8.00 model.reactions.EX_glc__D_e.lower_bound = 0.0 project.save_conditions(model, 'xylose_growth', carbon_source="EX_xyl__D_e") with open(os.path.join(ctx.path, "model_conditions.json")) as cond_path: ddict = json.load(cond_path) del ddict["growth_conditions"]["xylose_growth"]["objective_reactions"] with open(os.path.join(ctx.path, "model_conditions.json"), "w") as cond_path: json.dump(ddict, cond_path) too_model = project.load_conditions('xylose_growth', model=model, copy=True) model.reactions.EX_xyl__D_e.lower_bound = 0.00 assert model.reactions.EX_xyl__D_e.lower_bound != too_model.reactions.EX_xyl__D_e.lower_bound # Test bad objective handling ddict["growth_conditions"]["xylose_growth"]["objective_reactions"] = [ "NOT_REAL" ] with open(os.path.join(ctx.path, "model_conditions.json"), "w") as cond_path: json.dump(ddict, cond_path) too_model = project.load_conditions('xylose_growth', model=model, copy=True) assert too_model.reactions.BIOMASS_Ec_iAF1260_core_59p81M.objective_coefficient
def test_load_model(): """ Force exceptions to be thrown """ with pytest.raises(IOError): load_model('/this/path/does/not/exist') with pytest.raises(TypeError): # Create a fake file, format is not valid with tempfile.NamedTemporaryFile() as fp: load_model(fp.name, file_format="foo") with FakeProjectContext() as ctx: model = ctx.project.model load_medium(model, {}, copy=True) with pytest.raises(TypeError): load_medium(model, set()) with pytest.raises(TypeError): load_medium(set(), dict())
def test_validator(): """ Check models validate properly """ with FakeProjectContext() as ctx: # Valid model model = ctx.project.model result = validate_model(model) assert len(result['errors']) == 0 # Model that can't grow for re in model.exchanges: re.lower_bound = 0 result = validate_model(model) assert len(result['errors']) == 1 # model without constraints model = cobra.Model() result = validate_model(model) # Should issue warning, this assertion makes sure assert len(result['warnings']) == 1
def test_db(): with FakeProjectContext() as ctx: cache_location = os.path.join(ctx.path, '.gsmod_metacyc_db.json') db = metacyc.parse_db(METACYC_DB_PATH) db = metacyc.parse_db(METACYC_DB_PATH) _ = metacyc.build_universal_model(METACYC_DB_PATH, use_cache=True, cache_location=cache_location) _ = metacyc.build_universal_model(METACYC_DB_PATH, use_cache=True, cache_location=cache_location) _ = metacyc.build_universal_model(METACYC_DB_PATH, use_cache=False) model = ctx.model metacyc.add_pathway(model, reaction_ids=["ALCOHOL-DEHYDROG-RXN"], db_path=METACYC_DB_PATH) model = ctx.model metacyc.add_pathway(model, enzyme_ids=["EC-1.1.1.1"], db_path=METACYC_DB_PATH)
def test_add_essential_pathways(): """ Test adding of json test utility reactions, description = '', reaction_fluxes = None, models = None, designs = None, conditions = None, overwrite = False """ with FakeProjectContext() as fp: reactions = ['PYK'] # Test bad id with pytest.raises(TypeError): fp.project.add_essential_pathway(1, reactions=reactions) with pytest.raises(TypeError): fp.project.add_essential_pathway("foo", reactions=reactions, models="String") # Should work without exception fp.project.add_essential_pathway("foo", reactions=reactions) # Can't add the same design twice with pytest.raises(IOError): fp.project.add_essential_pathway("foo", reactions=reactions) with pytest.raises(KeyError): fp.project.add_essential_pathway("foo2", reactions=reactions, designs=["foo"]) with pytest.raises(KeyError): fp.project.add_essential_pathway("foo3", reactions=reactions, conditions=["foo"]) with pytest.raises(KeyError): fp.project.add_essential_pathway("foo4", reactions=reactions, models=["foo"])
def test_addmodel_validation(): # Test adding a model that fails validation with FakeProjectContext() as ctx: runner = CliRunner() # Create a fake model which can't grow npath = os.path.join(ctx.path, 'tmodel.xml') model = load_model(_CORE_MODEL_PATH) for media in model.medium: reaction = model.reactions.get_by_id(media) reaction.lower_bound = 0 reaction.upper_bound = 0 cobra.io.write_sbml_model(model, npath) # Try adding it to the project, it should fail with validation on result = runner.invoke(gsmodutils.cli.addmodel, [npath, '--project_path', ctx.path]) assert result.exit_code == -1 # Pass with validation off result = runner.invoke( gsmodutils.cli.addmodel, [npath, '--project_path', ctx.path, '--no-validate']) assert result.exit_code == 0
def test_import_conditions(): with FakeProjectContext() as ctx: runner = CliRunner() project = GSMProject(ctx.path) model = project.load_model() model.reactions.EX_xyl__D_e.lower_bound = -8.00 model.reactions.EX_glc__D_e.lower_bound = 0.0 save_path = os.path.join(ctx.path, 'tp.json') cobra.io.save_json_model(model, save_path) cid = 'xylose_growth' result = runner.invoke(gsmodutils.cli.iconditions, [save_path, cid, '--project_path', ctx.path]) assert result.exit_code == 0 # Check we can actually load these conditions mdl = project.load_conditions(cid) assert mdl.reactions.EX_xyl__D_e.lower_bound == -8.0 assert mdl.reactions.EX_glc__D_e.lower_bound == 0.0
def test_load_model(): """ Most of this is for code coverage :return: """ with FakeProjectContext() as ctx: ctx.add_fake_conditions() ctx.add_fake_designs() project = GSMProject(ctx.path) assert project.project_path == ctx.path model = GSModutilsModel(project) assert isinstance(model, cobra.Model) model.load_conditions("xyl_src") model.diff() model.diff(model) with pytest.raises(TypeError): model.diff("should break") # Test loading non design fails with pytest.raises(TypeError): GSModutilsModel(project, design={}) with pytest.raises(TypeError): GSModutilsModel({}) with pytest.raises(IOError): GSModutilsModel(project, mpath="/this/is/a/fake/path") model.save_model() cpy = model.to_cobra_model() assert not isinstance(cpy, GSModutilsModel)
def test_load_scrumpy(): with FakeProjectContext() as ctx: project = GSMProject(ctx.path) assert project.project_path == ctx.path model = GSModutilsModel(project) scrumpy_string = """ External(PROTON_i, "WATER") NADH_DH_ubi: "NADH" + "UBIQUINONE-8" + 4 PROTON_i -> "UBIQUINOL-8" + 3 PROTON_p + "NAD" ~ NADH_DH_meno: "NADH" + "Menaquinones" + 4 PROTON_i -> "Menaquinols" + 3 PROTON_p + "NAD" ~ Cytochrome_c_oxidase: 1/2 "OXYGEN-MOLECULE" + "UBIQUINOL-8" + 2 PROTON_i -> "UBIQUINONE-8" + "WATER" + 2 PROTON_p ~ ATPSynth: "ADP" + "Pi" + 4 PROTON_p -> "ATP" + "WATER" + 3 PROTON_i ~ ATPase: "ATP" -> "ADP" + "Pi" + x_ATPWork ~ """ model.add_scrumpy_reactions(scrumpy_string) assert "NADH_DH_ubi" in model.reactions assert "NADH_DH_meno" in model.reactions assert "Cytochrome_c_oxidase" in model.reactions assert "ATPSynth" in model.reactions assert "ATPase" in model.reactions
def test_essential_pathways(): """ Test adding of json test utility reactions, description = '', reaction_fluxes = None, models = None, designs = None, conditions = None, overwrite = False """ with FakeProjectContext() as fp: fp.add_fake_conditions() fp.add_fake_designs() reactions = ['PYK'] # Test a model fp.project.add_essential_pathway('model_test', reactions=reactions) with pytest.raises(IOError): fp.project.add_essential_pathway('model_test', reactions=reactions) # Add an essential pathway test for a design only fp.project.add_essential_pathway('design_test', reactions=reactions, designs=['mevalonate_cbb']) # Test conditions fp.project.add_essential_pathway('conditions_test', reactions=reactions, conditions=['xyl_src']) assert os.path.exists( os.path.join(fp.project.tests_dir, 'test_model_test.json')) assert os.path.exists( os.path.join(fp.project.tests_dir, 'test_design_test.json')) assert os.path.exists( os.path.join(fp.project.tests_dir, 'test_conditions_test.json')) # Test conditions designs and tester = fp.project.project_tester() tester.run_all()
def test_model_loader(): """ Model loader utility tests """ with FakeProjectContext(use_second_model=True) as ctx: ml = ModelLoader(ctx.project, "e_coli_core.json", None, None) ctx.add_fake_conditions() log = ResultRecord("TL") model = ml.load(log) assert os.path.basename(model.mpath) == "e_coli_core.json" assert model.design is None ctx.add_fake_designs() ml = ModelLoader(ctx.project, None, "xyl_src", "mevalonate_cbb") log = ResultRecord("TL2") model = ml.load(log) treac = model.reactions.get_by_id("EX_xyl__D_e") assert isinstance(model.design, StrainDesign) assert model.design.id == "mevalonate_cbb" assert treac.lower_bound == -8.0 ml = ModelLoader(ctx.project, None, "xyl_src", None) log = ResultRecord("TL2") model = ml.load(log) treac = model.reactions.get_by_id("EX_xyl__D_e") assert treac.lower_bound == -8.0
def test_docker(): with FakeProjectContext() as ctx: # Add some conditions and a design with a parent project = GSMProject(ctx.path) model = project.load_model() model.reactions.EX_xyl__D_e.lower_bound = -8.00 model.reactions.EX_glc__D_e.lower_bound = 0.0 project.save_conditions(model, 'xylose_growth') nr = model.reactions.EX_glc__D_e.copy() model.remove_reactions(["EX_glc__D_e"]) project.save_design(model, 'tt1', 'tt1') model.add_reactions([nr]) project.save_design(model, 'tt2', 'tt2', parent='tt1') runner = CliRunner() result = runner.invoke(gsmodutils.cli.docker, ['--project_path', ctx.path]) assert result.exit_code == 0 result = runner.invoke(gsmodutils.cli.docker, ['--project_path', ctx.path, '--overwrite']) assert result.exit_code == 0
def test_py_design(): """ Tests a working py_design """ py_design = """ from gsmodutils.utils import design_annotation @design_annotation(name="tester") def gsmdesign_tester(model, project): '''This is the description''' reaction = model.reactions.get_by_id("ATPM") reaction.bounds = (-999, 999) return model @design_annotation() def gsmdesign_no_return(model, project): pass @design_annotation() def gsmdesign_bad_prototype(model): return model @design_annotation(conditions="xylose_growth", description="overridden description") def gsmdesign_uses_conditions(model, project): '''orginal description''' return model @design_annotation(base_model="e_coli_core.json") def gsmdesign_uses_base_model(model, project): return model @design_annotation(base_model="e_coli_core") def gsmdesign_bad_base_model(model, project): return model """ broken_file = """ THIS IS CLEARLY BROKEN PYTHON SYNTAX """ with FakeProjectContext(use_second_model=True) as ctx: project = GSMProject(ctx.path) ndpath = os.path.join(project.design_path, 'design_t1.py') # Write the design with open(ndpath, 'w+') as desf: desf.write(py_design) # The file is broken but but the project should still load ndpath = os.path.join(project.design_path, 'design_broken.py') with open(ndpath, 'w+') as desb: desb.write(broken_file) # Should load without error design = project.get_design("t1_tester") assert design.is_pydesign assert design.name == "tester" assert design.parent is None assert design.description == "This is the description" mdl = design.load() # Check that the code has executed reaction = mdl.reactions.get_by_id("ATPM") assert reaction.lower_bound == -999 assert reaction.upper_bound == 999 model = project.model # Growth on xylose instead of glucose model.reactions.EX_xyl__D_e.lower_bound = -8.00 model.reactions.EX_glc__D_e.lower_bound = 0.0 project.save_conditions(model, 'xylose_growth', carbon_source="EX_xyl__D_e") design = project.get_design("t1_uses_conditions") assert design.description == "overridden description" assert design.conditions == "xylose_growth" mdl = design.load() assert mdl.reactions.EX_glc__D_e.lower_bound == 0 assert mdl.reactions.EX_xyl__D_e.lower_bound == -8.00 with pytest.raises(DesignError): project.get_design("t1_no_return") with pytest.raises(DesignError): project.get_design("t1_bad_prototype") design = project.get_design("t1_uses_base_model") assert design.base_model == "e_coli_core.json" assert len(design.load().reactions) == 95 # Make sure the base model is loaded with pytest.raises(DesignError): project.get_design("t1_bad_base_model")