When writing fbc-v2 with SBML L3V2 and KeyValuePairs the file is correctly written, but errors exist on reading.
See example code and output below
"""
Test bed for FBC version 3.
For latest SBML fbc v3 specification see
https://sourceforge.net/p/sbml/code/26312/tree/trunk/specifications/sbml-level-3/version-1/fbc/spec/main.pdf?format=raw
"""
import libsbml
from logging import getLogger
logger = getLogger(__name__)
def check(value: int, message: str) -> bool:
"""Check the libsbml return value and prints message if something happened.
If 'value' is None, prints an error message constructed using
'message' and then exits with status code 1. If 'value' is an integer,
it assumes it is a libSBML return status code. If the code value is
LIBSBML_OPERATION_SUCCESS, returns without further action; if it is not,
prints an error message constructed using 'message' along with text from
libSBML explaining the meaning of the code, and exits with status code 1.
"""
valid = True
if value is None:
logger.error(f"Error: LibSBML returned a null value trying to <{message}>.")
valid = False
elif isinstance(value, int):
if value != libsbml.LIBSBML_OPERATION_SUCCESS:
logger.error(f"Error encountered trying to '{message}'.")
logger.error(
f"LibSBML returned error code {str(value)}: "
f"{libsbml.OperationReturnValue_toString(value).strip()}"
)
valid = False
return valid
# create document with new fbc version 3 namespace
sbmlns: libsbml.SBMLNamespaces = libsbml.SBMLNamespaces(3, 2)
sbmlns.addPkgNamespace("fbc", 3)
doc: libsbml.SBMLDocument = libsbml.SBMLDocument(sbmlns)
doc_fbc: libsbml.FbcSBMLDocumentPlugin = doc.getPlugin("fbc")
doc_fbc.setRequired(False)
model: libsbml.Model = doc.createModel()
model_fbc: libsbml.FbcModelPlugin = model.getPlugin("fbc")
print(model_fbc)
model_fbc.setStrict(True)
# Support for key value pairs exists
c: libsbml.Compartment = model.createCompartment()
c.setId("c1")
c.setSize(1.0)
c.setConstant(True)
s1: libsbml.Species = model.createSpecies()
s1.setId("s1")
s1.setCompartment("c1")
s1.setInitialConcentration(1.0)
s1.setConstant(True)
s1.setHasOnlySubstanceUnits(False)
s1.setBoundaryCondition(False)
# KeyValue Pair
s1_fbc: libsbml.FbcSpeciesPlugin = s1.getPlugin("fbc")
kvp_list: libsbml.ListOfKeyValuePairs = s1_fbc.getListOfKeyValuePairs()
kvp_list.setXmlns("http://sbml.org/fbc/keyvaluepair")
kvp: libsbml.KeyValuePair = kvp_list.createKeyValuePair()
check(kvp.setKey("testdata"), "Set Key on KeyValuePair")
check(kvp.setValue("1.0"), "Set Value on KeyValuePair")
sbml_str: str = libsbml.writeSBMLToString(doc)
print("-" * 80)
print(sbml_str)
print("-" * 80)
# checking that SBML string can be read again
doc2 = libsbml.readSBMLFromString(sbml_str)
if doc2.getNumErrors() > 0:
if doc2.getError(0).getErrorId() == libsbml.XMLFileUnreadable:
err_message = "Unreadable SBML file"
elif doc2.getError(0).getErrorId() == libsbml.XMLFileOperationError:
err_message = "Problems reading SBML file: XMLFileOperationError"
else:
err_message = "SBMLDocumentErrors encountered while reading the SBML file."
# log_sbml_errors_for_doc(doc)
logger.error(f"`read_sbml` error `{err_message}`")
for k in range(doc2.getNumErrors()):
error: libsbml.SBMLError = doc2.getError(k)
print(f"Error {k}")
print(error.getMessage())
Results in
<?xml version="1.0" encoding="UTF-8"?>
<sbml xmlns="http://www.sbml.org/sbml/level3/version2/core" xmlns:fbc="http://www.sbml.org/sbml/level3/version1/fbc/version3" level="3" version="2" fbc:required="false">
<model fbc:strict="true">
<listOfCompartments>
<compartment id="c1" size="1" constant="true"/>
</listOfCompartments>
<listOfSpecies>
<species id="s1" compartment="c1" initialConcentration="1" hasOnlySubstanceUnits="false" boundaryCondition="false" constant="true">
<annotation>
<listOfKeyValuePairs xmlns="http://www.sbml.org/sbml/level3/version1/fbc/version3">
<keyValuePair key="testdata" value="1.0"/>
</listOfKeyValuePairs>
</annotation>
</species>
</listOfSpecies>
</model>
</sbml>
`read_sbml` error `SBMLDocumentErrors encountered while reading the SBML file.`
Error 0
A <keyValuePair> object may have the optional SBML Level 3 Core attributes 'metaid' and 'sboTerm'. No other attributes from the SBML Level 3 Core namespaces are permitted on a <keyValuePair>.
Attribute 'value' is not part of the definition of an SBML Level 3 Version 2 Package fbc Version 3 <keyValuePair> element.
Error 1
A <keyValuePair> object may have the optional SBML Level 3 Core attributes 'metaid' and 'sboTerm'. No other attributes from the SBML Level 3 Core namespaces are permitted on a <keyValuePair>.
Attribute 'value' is not part of the definition of an SBML Level 3 Version 2 Package fbc Version 3 <keyValuePair> element.
When writing fbc-v2 with SBML L3V2 and KeyValuePairs the file is correctly written, but errors exist on reading.
See example code and output below
Results in