Repository navigation
v0.3.0
Parity pass against the MATLAB GECKO Toolbox: geckopy's core functions now reproduce every value GECKO's own unit-test suite pins down.
Added
tests/test_gecko_matlab_parity.py— a 1:1 port of GECKO'stest/unit_tests/geckoCoreFunctionTests.m(47 tests, MATLAB test casestc0001–tc0013), run against the sameecTestGEMfixture MATLAB uses. Every expected value is copied verbatim from the MATLAB sources rather than re-derived from geckopy's output, so the file is the executable definition of "geckopy builds the same ecModel as GECKO". It needs no MATLAB to run and coversmakeEcModel(full and light),applyComplexData,setProtPoolSize,getECfromGEM,getECfromDatabase, save/load round-trip,fuzzyKcatMatching,writeDLKcatInput,mergeDLKcatAndFuzzyKcats,selectKcatValue,applyKcatConstraints,getKcatAcrossIsozymes,applyCustomKcats,findMetSmilesand the proteomics-integration chain.
Fixed
make_ec_modelsorts identifiers for full models, as MATLABmakeEcModeldoes (sortIdentifiers, line 203, full models only, before the protein pseudoreactions are appended). geckopy kept the input GEM's reaction order, so a full ecModel came out with the same reactions in a different order from MATLAB's — visible in the saved YAML and in every downstream table that followsec.rxnsorder.write_dlkcat_inputemits rows in reaction order, matching MATLAB's column-majorfind(clearedRedS < 0). numpy'swhereis row-major, so geckopy grouped the DLKcat input by substrate instead of by reaction.EcModel.copy()clones theecsubstructure.cobra.Model.copyrebuilds the network but carries every other attribute over by reference, somodel.copy().ecwas the sameEcDataobject asmodel.ec: writing a kcat, eccode, source, conc or coupling coefficient on the copy silently changed the model it was copied from. The copy'senzymesview was likewise still bound to the original model, so reads and writes throughmodel.enzymeswent to the wrong model.copy()now clonesecand rebindsenzymes, giving the value semantics MATLAB GECKO has throughout.adapterstays a shared reference (project configuration, not model state).copy.deepcopy(model)was already correct and is unchanged.- Reverse (
_REV) reactions keep their EC code, via a fix in raven-toolbox'sconvert_to_irreversible(it now copies annotations, subsystem and notes onto the reverse reaction, as MATLAB'sconvertToIrrevcopieseccodes/rxnMiriams/subSystems/rxnNotes). Without itfill_eccodes_from_gemreturned''for every_REVreaction, fuzzy BRENDA matching found no kcat, and reverse directions were left unconstrained. Requires raven-toolbox at or after that fix. copy.deepcopy(ec_model)(and of anycobra.Model) no longerRecursionErrors on Python 3.14. The cause was in cobra, not geckopy:Reaction.__copy__/__deepcopy__delegated tosuper()as a way to avoid infinitely recursing into themselves, but that trick relies oncopymemoizing an object before recursing into its state, and Python 3.14'scopymodule no longer does so for that code path. Every reaction holds its metabolites and every metabolite holds the reactions it participates in, so the resulting cycle exists in any real model, full ecModels included — deep-copying one recursed until the interpreter's recursion limit gave out. Fixed upstream in cobra 0.31.0 by deleting the overrides; requires cobra at or after 0.31.1.examples/yeast-GEM's adapter config used a rejected pydantic field.model_adapter.tomlsetuniprot.tax_id, butModelParameters's schema (additionalProperties=false) has no such field — it's calledid, and already defaults to the taxonomy id — soModelAdapter.from_folderraised a validation error on this folder unconditionally. A parametrized regression test now runs over everyexamples/subfolder so schema drift like this is caught for any future adapter config too. (#34)
Documentation
- Docstrings across geckopy's source and tests reviewed for clarity and accuracy:
MATLAB-COMPATcomparison paragraphs replaced with plain statements of current behavior, other historical/regression narration dropped, and several docstrings that no longer matched the code corrected. Comment/docstring-only; no functional changes. (#36) protein_pool.py's module docstring no longer claimsprot_pool_exchange's direction diverges from MATLAB pending a "future I/O layer". GECKO MATLAB'smakeEcModel.malready writes the same forward (lb=0,ub=1000) convention as geckopy; the reverse convention only applies to legacy pre-GECKO-4 files, whichload_ec_model.pyalready normalizes on load. (#38)mw.py's staleMATLAB-COMPATcomments removed now thatcalculate_mwmatches GECKO MATLAB's current water-mass constant (18.01528) and mean X-residue mass (118.885), closed upstream as GECKO#459. No behavioral change — the code already computed the now-matching values. (#39)
Internal
- Removed the dead
_run_preprocessstub fromtest_populate_ec: an empty helper (docstring and comments, no body) that was never called. The preprocessing stages it described are already exercised elsewhere. (#37)
Notes
merge_kcatsis n-ary and concatenates surviving rows list by list, so the equivalent of MATLAB'smergeDLKcatAndFuzzyKcats(dlkcat, fuzzy)— which always emits fuzzy rows first regardless of argument order — ismerge_kcats(fuzzy, dlkcat, ...). The deprecatedmerge_dlkcat_and_fuzzy_kcatsalias ismerge_kcats, so it follows the geckopy convention, not MATLAB's signature. Row order has no numerical effect:apply_kcat_listaggregates per reaction.
Full changelog: https://github.com/SysBioChalmers/geckopy/blob/main/CHANGELOG.md
Compare: v0.2.1...v0.3.0