Unverified Commit f938c8c4 authored by Laurent Heirendt's avatar Laurent Heirendt Committed by GitHub
Browse files

Merge pull request #37 from LCSB-BioCore/mk-strings

Sanitize string handling, make species' names optional
parents 7d49a30a bd12b466
const VPtr = Ptr{Cvoid} const VPtr = Ptr{Cvoid}
"""
function get_string(x::VPtr, fn_sym)::Maybe{String}
C-call the SBML function `fn_sym` with a single parameter `x`, interpret the
result as a string and return it, or throw exception in case the pointer is
NULL.
"""
function get_string(x::VPtr, fn_sym)::String
str = ccall(sbml(fn_sym), Cstring, (VPtr,), x)
if str != C_NULL
return unsafe_string(str)
else
throw(DomainError(x, "Calling $fn_sym returned NULL, valid string expected."))
end
end
"""
function get_optional_string(x::VPtr, fn_sym)::Maybe{String}
Like [`get_string`](@Ref), but returns `nothing` instead of throwing an
exception.
This is used to get notes and annotations and several other things (see
`getNotes`, `getAnnotations`)
"""
function get_optional_string(x::VPtr, fn_sym)::Maybe{String}
str = ccall(sbml(fn_sym), Cstring, (VPtr,), x)
if str != C_NULL
return unsafe_string(str)
else
return nothing
end
end
""" """
function readSBML(fn::String)::Model function readSBML(fn::String)::Model
...@@ -12,7 +46,7 @@ function readSBML(fn::String)::Model ...@@ -12,7 +46,7 @@ function readSBML(fn::String)::Model
n_errs = ccall(sbml(:SBMLDocument_getNumErrors), Cuint, (VPtr,), doc) n_errs = ccall(sbml(:SBMLDocument_getNumErrors), Cuint, (VPtr,), doc)
for i = 0:n_errs-1 for i = 0:n_errs-1
err = ccall(sbml(:SBMLDocument_getError), VPtr, (VPtr, Cuint), doc, i) err = ccall(sbml(:SBMLDocument_getError), VPtr, (VPtr, Cuint), doc, i)
msg = unsafe_string(ccall(sbml(:XMLError_getMessage), Cstring, (VPtr,), err)) msg = get_string(err, :XMLError_getMessage)
@warn "SBML reported error: $msg" @warn "SBML reported error: $msg"
end end
if n_errs > 0 if n_errs > 0
...@@ -31,24 +65,8 @@ function readSBML(fn::String)::Model ...@@ -31,24 +65,8 @@ function readSBML(fn::String)::Model
end end
end end
""" getNotes(x::VPtr)::Maybe{String} = get_optional_string(x, :SBase_getNotesString)
function getOptionalString(x::VPtr, fn_sym)::Maybe{String} getAnnotation(x::VPtr)::Maybe{String} = get_optional_string(x, :SBase_getAnnotationString)
C-call the SBML function `fn_sym` with a single parameter `x`, interpret the result as a nullable string pointer and return appropriately.
This is used to get notes and annotations and several other things (see `getNotes`, `getAnnotations`)
"""
function getOptionalString(x::VPtr, fn_sym)::Maybe{String}
str = ccall(sbml(fn_sym), Cstring, (VPtr,), x)
if str != C_NULL
return unsafe_string(str)
else
return nothing
end
end
getNotes(x::VPtr)::Maybe{String} = getOptionalString(x, :SBase_getNotesString)
getAnnotation(x::VPtr)::Maybe{String} = getOptionalString(x, :SBase_getAnnotationString)
""" """
function getAssociation(x::VPtr)::GeneProductAssociation function getAssociation(x::VPtr)::GeneProductAssociation
...@@ -61,9 +79,7 @@ function getAssociation(x::VPtr)::GeneProductAssociation ...@@ -61,9 +79,7 @@ function getAssociation(x::VPtr)::GeneProductAssociation
# way, so we use a bit of a hack. # way, so we use a bit of a hack.
typecode = ccall(sbml(:SBase_getTypeCode), Cint, (VPtr,), x) typecode = ccall(sbml(:SBase_getTypeCode), Cint, (VPtr,), x)
if typecode == 808 # SBML_FBC_GENEPRODUCTREF if typecode == 808 # SBML_FBC_GENEPRODUCTREF
return GPARef( return GPARef(get_string(x, :GeneProductRef_getGeneProduct))
unsafe_string(ccall(sbml(:GeneProductRef_getGeneProduct), Cstring, (VPtr,), x)),
)
elseif typecode == 809 # SBML_FBC_AND elseif typecode == 809 # SBML_FBC_AND
return GPAAnd([ return GPAAnd([
getAssociation( getAssociation(
...@@ -96,7 +112,7 @@ function extractModel(mdl::VPtr)::Model ...@@ -96,7 +112,7 @@ function extractModel(mdl::VPtr)::Model
parameters = Dict{String,Float64}() parameters = Dict{String,Float64}()
for i = 1:ccall(sbml(:Model_getNumParameters), Cuint, (VPtr,), mdl) for i = 1:ccall(sbml(:Model_getNumParameters), Cuint, (VPtr,), mdl)
p = ccall(sbml(:Model_getParameter), VPtr, (VPtr, Cuint), mdl, i - 1) p = ccall(sbml(:Model_getParameter), VPtr, (VPtr, Cuint), mdl, i - 1)
id = unsafe_string(ccall(sbml(:Parameter_getId), Cstring, (VPtr,), p)) id = get_string(p, :Parameter_getId)
v = ccall(sbml(:Parameter_getValue), Cdouble, (VPtr,), p) v = ccall(sbml(:Parameter_getValue), Cdouble, (VPtr,), p)
parameters[id] = v parameters[id] = v
end end
...@@ -105,7 +121,7 @@ function extractModel(mdl::VPtr)::Model ...@@ -105,7 +121,7 @@ function extractModel(mdl::VPtr)::Model
units = Dict{String,Vector{UnitPart}}() units = Dict{String,Vector{UnitPart}}()
for i = 1:ccall(sbml(:Model_getNumUnitDefinitions), Cuint, (VPtr,), mdl) for i = 1:ccall(sbml(:Model_getNumUnitDefinitions), Cuint, (VPtr,), mdl)
ud = ccall(sbml(:Model_getUnitDefinition), VPtr, (VPtr, Cuint), mdl, i - 1) ud = ccall(sbml(:Model_getUnitDefinition), VPtr, (VPtr, Cuint), mdl, i - 1)
id = unsafe_string(ccall(sbml(:UnitDefinition_getId), Cstring, (VPtr,), ud)) id = get_string(ud, :UnitDefinition_getId)
units[id] = [ units[id] = [
begin begin
u = ccall(sbml(:UnitDefinition_getUnit), VPtr, (VPtr, Cuint), ud, j - 1) u = ccall(sbml(:UnitDefinition_getUnit), VPtr, (VPtr, Cuint), ud, j - 1)
...@@ -128,13 +144,9 @@ function extractModel(mdl::VPtr)::Model ...@@ -128,13 +144,9 @@ function extractModel(mdl::VPtr)::Model
# parse out compartment names # parse out compartment names
compartments = [ compartments = [
unsafe_string( get_string(
ccall(
sbml(:Compartment_getId),
Cstring,
(VPtr,),
ccall(sbml(:Model_getCompartment), VPtr, (VPtr, Cuint), mdl, i - 1), ccall(sbml(:Model_getCompartment), VPtr, (VPtr, Cuint), mdl, i - 1),
), :Compartment_getId,
) for i = 1:ccall(sbml(:Model_getNumCompartments), Cuint, (VPtr,), mdl) ) for i = 1:ccall(sbml(:Model_getNumCompartments), Cuint, (VPtr,), mdl)
] ]
...@@ -149,22 +161,15 @@ function extractModel(mdl::VPtr)::Model ...@@ -149,22 +161,15 @@ function extractModel(mdl::VPtr)::Model
# if the FBC plugin is present, try to get the chemical formula and charge # if the FBC plugin is present, try to get the chemical formula and charge
if 0 != if 0 !=
ccall(sbml(:FbcSpeciesPlugin_isSetChemicalFormula), Cint, (VPtr,), sp_fbc) ccall(sbml(:FbcSpeciesPlugin_isSetChemicalFormula), Cint, (VPtr,), sp_fbc)
formula = unsafe_string( formula = get_string(sp_fbc, :FbcSpeciesPlugin_getChemicalFormula)
ccall(
sbml(:FbcSpeciesPlugin_getChemicalFormula),
Cstring,
(VPtr,),
sp_fbc,
),
)
end end
if 0 != ccall(sbml(:FbcSpeciesPlugin_isSetCharge), Cint, (VPtr,), sp_fbc) if 0 != ccall(sbml(:FbcSpeciesPlugin_isSetCharge), Cint, (VPtr,), sp_fbc)
charge = ccall(sbml(:FbcSpeciesPlugin_getCharge), Cint, (VPtr,), sp_fbc) charge = ccall(sbml(:FbcSpeciesPlugin_getCharge), Cint, (VPtr,), sp_fbc)
end end
end end
species[unsafe_string(ccall(sbml(:Species_getId), Cstring, (VPtr,), sp))] = Species( species[get_string(sp, :Species_getId)] = Species(
unsafe_string(ccall(sbml(:Species_getName), Cstring, (VPtr,), sp)), get_optional_string(sp, :Species_getName),
unsafe_string(ccall(sbml(:Species_getCompartment), Cstring, (VPtr,), sp)), get_string(sp, :Species_getCompartment),
formula, formula,
charge, charge,
getNotes(sp), getNotes(sp),
...@@ -186,9 +191,8 @@ function extractModel(mdl::VPtr)::Model ...@@ -186,9 +191,8 @@ function extractModel(mdl::VPtr)::Model
) )
for j = 1:ccall(sbml(:Objective_getNumFluxObjectives), Cuint, (VPtr,), o) for j = 1:ccall(sbml(:Objective_getNumFluxObjectives), Cuint, (VPtr,), o)
fo = ccall(sbml(:Objective_getFluxObjective), VPtr, (VPtr, Cuint), o, j - 1) fo = ccall(sbml(:Objective_getFluxObjective), VPtr, (VPtr, Cuint), o, j - 1)
objectives_fbc[unsafe_string( objectives_fbc[get_string(fo, :FluxObjective_getReaction)] =
ccall(sbml(:FluxObjective_getReaction), Cstring, (VPtr,), fo), ccall(sbml(:FluxObjective_getCoefficient), Cdouble, (VPtr,), fo)
)] = ccall(sbml(:FluxObjective_getCoefficient), Cdouble, (VPtr,), fo)
end end
end end
end end
...@@ -206,11 +210,9 @@ function extractModel(mdl::VPtr)::Model ...@@ -206,11 +210,9 @@ function extractModel(mdl::VPtr)::Model
if kl != C_NULL if kl != C_NULL
for j = 1:ccall(sbml(:KineticLaw_getNumParameters), Cuint, (VPtr,), kl) for j = 1:ccall(sbml(:KineticLaw_getNumParameters), Cuint, (VPtr,), kl)
p = ccall(sbml(:KineticLaw_getParameter), VPtr, (VPtr, Cuint), kl, j - 1) p = ccall(sbml(:KineticLaw_getParameter), VPtr, (VPtr, Cuint), kl, j - 1)
id = unsafe_string(ccall(sbml(:Parameter_getId), Cstring, (VPtr,), p)) id = get_string(p, :Parameter_getId)
pval = () -> ccall(sbml(:Parameter_getValue), Cdouble, (VPtr,), p) pval = () -> ccall(sbml(:Parameter_getValue), Cdouble, (VPtr,), p)
punit = punit = () -> get_string(p, :Parameter_getUnits)
() ->
unsafe_string(ccall(sbml(:Parameter_getUnits), Cstring, (VPtr,), p))
if id == "LOWER_BOUND" if id == "LOWER_BOUND"
lb = (pval(), punit()) lb = (pval(), punit())
elseif id == "UPPER_BOUND" elseif id == "UPPER_BOUND"
...@@ -229,15 +231,13 @@ function extractModel(mdl::VPtr)::Model ...@@ -229,15 +231,13 @@ function extractModel(mdl::VPtr)::Model
# can make something out of it. # can make something out of it.
re_fbc = ccall(sbml(:SBase_getPlugin), VPtr, (VPtr, Cstring), re, "fbc") re_fbc = ccall(sbml(:SBase_getPlugin), VPtr, (VPtr, Cstring), re, "fbc")
if re_fbc != C_NULL if re_fbc != C_NULL
fbcb = fbcb = get_optional_string(re_fbc, :FbcReactionPlugin_getLowerFluxBound)
ccall(sbml(:FbcReactionPlugin_getLowerFluxBound), Cstring, (VPtr,), re_fbc) if !isnothing(fbcb) && haskey(parameters, fbcb)
if fbcb != C_NULL && haskey(parameters, unsafe_string(fbcb)) lb = (parameters[fbcb], "[fbc]")
lb = (parameters[unsafe_string(fbcb)], "[fbc]")
end end
fbcb = fbcb = get_optional_string(re_fbc, :FbcReactionPlugin_getUpperFluxBound)
ccall(sbml(:FbcReactionPlugin_getUpperFluxBound), Cstring, (VPtr,), re_fbc) if !isnothing(fbcb) && haskey(parameters, fbcb)
if fbcb != C_NULL && haskey(parameters, unsafe_string(fbcb)) ub = (parameters[fbcb], "[fbc]")
ub = (parameters[unsafe_string(fbcb)], "[fbc]")
end end
end end
...@@ -245,9 +245,7 @@ function extractModel(mdl::VPtr)::Model ...@@ -245,9 +245,7 @@ function extractModel(mdl::VPtr)::Model
stoi = Dict{String,Float64}() stoi = Dict{String,Float64}()
add_stoi = add_stoi =
(sr, factor) -> (sr, factor) ->
stoi[unsafe_string( stoi[get_string(sr, :SpeciesReference_getSpecies)] =
ccall(sbml(:SpeciesReference_getSpecies), Cstring, (VPtr,), sr),
)] =
ccall(sbml(:SpeciesReference_getStoichiometry), Cdouble, (VPtr,), sr) * ccall(sbml(:SpeciesReference_getStoichiometry), Cdouble, (VPtr,), sr) *
factor factor
...@@ -277,7 +275,7 @@ function extractModel(mdl::VPtr)::Model ...@@ -277,7 +275,7 @@ function extractModel(mdl::VPtr)::Model
end end
end end
reid = unsafe_string(ccall(sbml(:Reaction_getId), Cstring, (VPtr,), re)) reid = get_string(re, :Reaction_getId)
reactions[reid] = Reaction( reactions[reid] = Reaction(
stoi, stoi,
lb, lb,
...@@ -301,12 +299,12 @@ function extractModel(mdl::VPtr)::Model ...@@ -301,12 +299,12 @@ function extractModel(mdl::VPtr)::Model
i - 1, i - 1,
) )
id = getOptionalString(gp, :GeneProduct_getId) # IDs don't need to be set id = get_optional_string(gp, :GeneProduct_getId) # IDs don't need to be set
if id != nothing if id != nothing
gene_products[id] = GeneProduct( gene_products[id] = GeneProduct(
getOptionalString(gp, :GeneProduct_getName), get_optional_string(gp, :GeneProduct_getName),
getOptionalString(gp, :GeneProduct_getLabel), get_optional_string(gp, :GeneProduct_getLabel),
getNotes(gp), getNotes(gp),
getAnnotation(gp), getAnnotation(gp),
) )
......
...@@ -78,7 +78,7 @@ Species metadata -- contains a human-readable `name`, a `compartment` ...@@ -78,7 +78,7 @@ Species metadata -- contains a human-readable `name`, a `compartment`
identifier, `formula`, `charge`, and additional `notes` and `annotation`. identifier, `formula`, `charge`, and additional `notes` and `annotation`.
""" """
struct Species struct Species
name::String name::Maybe{String}
compartment::String compartment::String
formula::Maybe{String} formula::Maybe{String}
charge::Maybe{Int} charge::Maybe{Int}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment