Commit e5975038 by Maarten L. Hekkelman

- changed compound::is_known_peptide/is_know_base

- Add audit_conform only if file is really valid
- Added reconstruction code for PDBx
parent 4e19d548
...@@ -564,6 +564,7 @@ if(BUILD_TESTING) ...@@ -564,6 +564,7 @@ if(BUILD_TESTING)
rename-compound rename-compound
sugar sugar
spinner spinner
reconstruction
validate-pdbx) validate-pdbx)
foreach(CIFPP_TEST IN LISTS CIFPP_tests) foreach(CIFPP_TEST IN LISTS CIFPP_tests)
......
...@@ -166,6 +166,12 @@ class compound ...@@ -166,6 +166,12 @@ class compound
return m_id == "HOH" or m_id == "H2O" or m_id == "WAT"; return m_id == "HOH" or m_id == "H2O" or m_id == "WAT";
} }
/** \brief Return whether this compound has a type of either 'peptide linking' or 'L-peptide linking' */
bool is_peptide() const;
/** \brief Return whether this compound has a type of either 'DNA linking' or 'RNA linking' */
bool is_base() const;
char one_letter_code() const { return m_one_letter_code; }; ///< Return the one letter code to use in a canonical sequence. If unknown the value '\0' is returned char one_letter_code() const { return m_one_letter_code; }; ///< Return the one letter code to use in a canonical sequence. If unknown the value '\0' is returned
std::string parent_id() const { return m_parent_id; }; ///< Return the parent id code in case a parent is specified (e.g. MET for MSE) std::string parent_id() const { return m_parent_id; }; ///< Return the parent id code in case a parent is specified (e.g. MET for MSE)
...@@ -237,25 +243,53 @@ class compound_factory ...@@ -237,25 +243,53 @@ class compound_factory
void pop_dictionary(); void pop_dictionary();
/// Return whether @a res_name is a valid and known peptide /// Return whether @a res_name is a valid and known peptide
[[deprecated("use is_peptide or is_std_peptide instead)")]]
bool is_known_peptide(const std::string &res_name) const; bool is_known_peptide(const std::string &res_name) const;
/// Return whether @a res_name is a valid and known base /// Return whether @a res_name is a valid and known base
[[deprecated("use is_base or is_std_base instead)")]]
bool is_known_base(const std::string &res_name) const; bool is_known_base(const std::string &res_name) const;
/// Return whether @a res_name is a peptide
bool is_peptide(std::string_view res_name) const;
/// Return whether @a res_name is a base
bool is_base(std::string_view res_name) const;
/// Return whether @a res_name is one of the standard peptides
bool is_std_peptide(std::string_view res_name) const;
/// Return whether @a res_name is one of the standard bases
bool is_std_base(std::string_view res_name) const;
/// Return whether @a res_name is a monomer (either base or peptide)
bool is_monomer(std::string_view res_name) const;
/// Return whether @a res_name is one of the standard bases or peptides
bool is_std_monomer(std::string_view res_name) const
{
return is_std_base(res_name) or is_std_peptide(res_name);
}
bool is_water(std::string_view res_name) const
{
return res_name == "HOH" or res_name == "H2O" or res_name == "WAT";
}
/// \brief Create the compound object for \a id /// \brief Create the compound object for \a id
/// ///
/// This will create the compound instance for \a id if it doesn't exist already. /// This will create the compound instance for \a id if it doesn't exist already.
/// The result is owned by this factory and should not be deleted by the user. /// The result is owned by this factory and should not be deleted by the user.
/// \param id The compound ID, a three letter code usually /// \param id The compound ID, a three letter code usually
/// \result The compound, or nullptr if it could not be created (missing info) /// \result The compound, or nullptr if it could not be created (missing info)
const compound *create(std::string id); const compound *create(std::string_view id);
~compound_factory(); ~compound_factory();
CIFPP_EXPORT static const std::map<std::string, char> kAAMap, ///< Globally accessible static list of the default amino acids CIFPP_EXPORT static const std::map<std::string, char> kAAMap, ///< Globally accessible static list of the default amino acids
kBaseMap; ///< Globally accessible static list of the default bases kBaseMap; ///< Globally accessible static list of the default bases
void report_missing_compound(const std::string &compound_id); void report_missing_compound(std::string_view compound_id);
private: private:
compound_factory(); compound_factory();
......
...@@ -107,6 +107,15 @@ class datablock : public std::list<category> ...@@ -107,6 +107,15 @@ class datablock : public std::list<category>
bool is_valid() const; bool is_valid() const;
/** /**
* @brief Validates the content of this datablock and all its content
* and updates or removes the audit_conform category to match the result.
*
* @return true If the content is valid
* @return false If the content is not valid
*/
bool is_valid();
/**
* @brief Validates all contained data for valid links between parents and children * @brief Validates all contained data for valid links between parents and children
* as defined in the validator * as defined in the validator
* *
......
...@@ -109,9 +109,10 @@ inline void write(const std::filesystem::path &p, const file &f) ...@@ -109,9 +109,10 @@ inline void write(const std::filesystem::path &p, const file &f)
* *
* \param file The cif::file that hopefully contains some valid data * \param file The cif::file that hopefully contains some valid data
* \param dictionary The mmcif dictionary to use * \param dictionary The mmcif dictionary to use
* \result Returns true if the resulting file is valid
*/ */
void reconstruct_pdbx(file &pdbx_file, std::string_view dictionary = "mmcif_pdbx"); bool reconstruct_pdbx(file &pdbx_file, std::string_view dictionary = "mmcif_pdbx");
/** \brief This is an extension to cif::validator, use the logic in common /** \brief This is an extension to cif::validator, use the logic in common
* PDBx files to see if the file is internally consistent. * PDBx files to see if the file is internally consistent.
......
...@@ -170,6 +170,33 @@ inline std::error_condition make_error_condition(validation_error e) ...@@ -170,6 +170,33 @@ inline std::error_condition make_error_condition(validation_error e)
// -------------------------------------------------------------------- // --------------------------------------------------------------------
class validation_exception : public std::runtime_error
{
public:
validation_exception(validation_error err)
: validation_exception(make_error_code(err))
{
}
validation_exception(validation_error err, std::string_view category)
: validation_exception(make_error_code(err), category)
{
}
validation_exception(validation_error err, std::string_view category, std::string_view item)
: validation_exception(make_error_code(err), category, item)
{
}
validation_exception(std::error_code ec);
validation_exception(std::error_code ec, std::string_view category);
validation_exception(std::error_code ec, std::string_view category, std::string_view item);
};
// --------------------------------------------------------------------
/** @brief the primitive types known */ /** @brief the primitive types known */
enum class DDL_PrimitiveType enum class DDL_PrimitiveType
{ {
......
...@@ -2712,4 +2712,96 @@ _pdbx_chem_comp_audit.processing_site ...@@ -2712,4 +2712,96 @@ _pdbx_chem_comp_audit.processing_site
HIS "Create component" 1999-07-08 EBI HIS "Create component" 1999-07-08 EBI
HIS "Modify descriptor" 2011-06-04 RCSB HIS "Modify descriptor" 2011-06-04 RCSB
# #
data_HOH
#
_chem_comp.id HOH
_chem_comp.name WATER
_chem_comp.type NON-POLYMER
_chem_comp.pdbx_type HETAS
_chem_comp.formula "H2 O"
_chem_comp.mon_nstd_parent_comp_id ?
_chem_comp.pdbx_synonyms ?
_chem_comp.pdbx_formal_charge 0
_chem_comp.pdbx_initial_date 1999-07-08
_chem_comp.pdbx_modified_date 2011-06-04
_chem_comp.pdbx_ambiguous_flag N
_chem_comp.pdbx_release_status REL
_chem_comp.pdbx_replaced_by ?
_chem_comp.pdbx_replaces MTO
_chem_comp.formula_weight 18.015
_chem_comp.one_letter_code ?
_chem_comp.three_letter_code HOH
_chem_comp.pdbx_model_coordinates_details ?
_chem_comp.pdbx_model_coordinates_missing_flag N
_chem_comp.pdbx_ideal_coordinates_details ?
_chem_comp.pdbx_ideal_coordinates_missing_flag N
_chem_comp.pdbx_model_coordinates_db_code 1NHE
_chem_comp.pdbx_subcomponent_list ?
_chem_comp.pdbx_processing_site RCSB
# #
loop_
_chem_comp_atom.comp_id
_chem_comp_atom.atom_id
_chem_comp_atom.alt_atom_id
_chem_comp_atom.type_symbol
_chem_comp_atom.charge
_chem_comp_atom.pdbx_align
_chem_comp_atom.pdbx_aromatic_flag
_chem_comp_atom.pdbx_leaving_atom_flag
_chem_comp_atom.pdbx_stereo_config
_chem_comp_atom.model_Cartn_x
_chem_comp_atom.model_Cartn_y
_chem_comp_atom.model_Cartn_z
_chem_comp_atom.pdbx_model_Cartn_x_ideal
_chem_comp_atom.pdbx_model_Cartn_y_ideal
_chem_comp_atom.pdbx_model_Cartn_z_ideal
_chem_comp_atom.pdbx_component_atom_id
_chem_comp_atom.pdbx_component_comp_id
_chem_comp_atom.pdbx_ordinal
HOH O O O 0 1 N N N -23.107 18.401 -21.626 -0.064 0.000 0.000 O HOH 1
HOH H1 1H H 0 1 N N N -22.157 18.401 -21.626 0.512 0.000 -0.776 H1 HOH 2
HOH H2 2H H 0 1 N N N -23.424 18.401 -20.730 0.512 0.000 0.776 H2 HOH 3
# #
loop_
_chem_comp_bond.comp_id
_chem_comp_bond.atom_id_1
_chem_comp_bond.atom_id_2
_chem_comp_bond.value_order
_chem_comp_bond.pdbx_aromatic_flag
_chem_comp_bond.pdbx_stereo_config
_chem_comp_bond.pdbx_ordinal
HOH O H1 SING N N 1
HOH O H2 SING N N 2
# #
loop_
_pdbx_chem_comp_descriptor.comp_id
_pdbx_chem_comp_descriptor.type
_pdbx_chem_comp_descriptor.program
_pdbx_chem_comp_descriptor.program_version
_pdbx_chem_comp_descriptor.descriptor
HOH SMILES ACDLabs 10.04 O
HOH SMILES_CANONICAL CACTVS 3.341 O
HOH SMILES CACTVS 3.341 O
HOH SMILES_CANONICAL "OpenEye OEToolkits" 1.5.0 O
HOH SMILES "OpenEye OEToolkits" 1.5.0 O
HOH InChI InChI 1.03 InChI=1S/H2O/h1H2
HOH InChIKey InChI 1.03 XLYOFNOQVPJJNP-UHFFFAOYSA-N
# #
loop_
_pdbx_chem_comp_identifier.comp_id
_pdbx_chem_comp_identifier.type
_pdbx_chem_comp_identifier.program
_pdbx_chem_comp_identifier.program_version
_pdbx_chem_comp_identifier.identifier
HOH "SYSTEMATIC NAME" ACDLabs 10.04 water
HOH "SYSTEMATIC NAME" "OpenEye OEToolkits" 1.5.0 oxidane
# #
loop_
_pdbx_chem_comp_audit.comp_id
_pdbx_chem_comp_audit.action_type
_pdbx_chem_comp_audit.date
_pdbx_chem_comp_audit.processing_site
HOH "Create component" 1999-07-08 RCSB
HOH "Modify descriptor" 2011-06-04 RCSB
##
...@@ -644,7 +644,7 @@ iset category::key_items() const ...@@ -644,7 +644,7 @@ iset category::key_items() const
throw std::runtime_error("No Validator specified"); throw std::runtime_error("No Validator specified");
if (m_cat_validator == nullptr) if (m_cat_validator == nullptr)
m_validator->report_error(validation_error::undefined_category); throw validation_exception(validation_error::undefined_category);
iset result; iset result;
for (auto &iv : m_cat_validator->m_item_validators) for (auto &iv : m_cat_validator->m_item_validators)
...@@ -659,7 +659,7 @@ std::set<uint16_t> category::key_item_indices() const ...@@ -659,7 +659,7 @@ std::set<uint16_t> category::key_item_indices() const
throw std::runtime_error("No Validator specified"); throw std::runtime_error("No Validator specified");
if (m_cat_validator == nullptr) if (m_cat_validator == nullptr)
m_validator->report_error(validation_error::undefined_category); throw validation_exception(validation_error::undefined_category);
std::set<uint16_t> result; std::set<uint16_t> result;
for (auto &k : m_cat_validator->m_keys) for (auto &k : m_cat_validator->m_keys)
...@@ -831,7 +831,7 @@ bool category::is_valid() const ...@@ -831,7 +831,7 @@ bool category::is_valid() const
if (iv == nullptr) if (iv == nullptr)
{ {
m_validator->report_error(validation_error::unknown_item, m_name, m_items[cix].m_name, false); // no need to report, should have been reported already above
result = false; result = false;
continue; continue;
} }
...@@ -1348,20 +1348,32 @@ void category::update_value(const std::vector<row_handle> &rows, std::string_vie ...@@ -1348,20 +1348,32 @@ void category::update_value(const std::vector<row_handle> &rows, std::string_vie
auto colIx = get_item_ix(item_name); auto colIx = get_item_ix(item_name);
if (colIx >= m_items.size()) if (colIx >= m_items.size())
throw std::runtime_error("Invalid item " + std::string{ value } + " for " + m_name); throw validation_exception(validation_error::unknown_item, m_name, item_name);
auto &col = m_items[colIx]; auto &col = m_items[colIx];
// check the value // check the value
if (col.m_validator) if (col.m_validator)
(*col.m_validator)(value); {
std::error_code ec;
col.m_validator->validate_value(value, ec);
if (ec)
throw validation_exception(ec, m_name, item_name);
}
// first some sanity checks, what was the old value and is it the same for all rows? // first some sanity checks, what was the old value and is it the same for all rows?
std::string oldValue{ rows.front()[item_name].text() }; std::string oldValue{ rows.front()[item_name].text() };
for (auto row : rows) for (auto row : rows)
{ {
if (oldValue != row[item_name].text()) if (oldValue != row[item_name].text())
throw std::runtime_error("Inconsistent old values in update_value"); {
std::ostringstream os;
os << "Inconsistent old values in update_value, trying to set " << std::quoted(value)
<< " as value for item " << item_name << " in category " << m_name;
throw std::runtime_error(os.str());
}
} }
if (oldValue == value) // no need to do anything if (oldValue == value) // no need to do anything
......
...@@ -311,6 +311,18 @@ float compound::bond_length(const std::string &atomId_1, const std::string &atom ...@@ -311,6 +311,18 @@ float compound::bond_length(const std::string &atomId_1, const std::string &atom
} }
// -------------------------------------------------------------------- // --------------------------------------------------------------------
bool compound::is_peptide() const
{
return iequals(m_type, "l-peptide linking") or iequals(m_type, "peptide linking");
}
bool compound::is_base() const
{
return iequals(m_type, "dna linking") or iequals(m_type, "rna linking");
}
// --------------------------------------------------------------------
// known amino acids and bases // known amino acids and bases
const std::map<std::string, char> compound_factory::kAAMap{ const std::map<std::string, char> compound_factory::kAAMap{
...@@ -660,25 +672,67 @@ void compound_factory::pop_dictionary() ...@@ -660,25 +672,67 @@ void compound_factory::pop_dictionary()
m_impl = m_impl->next(); m_impl = m_impl->next();
} }
const compound *compound_factory::create(std::string id) const compound *compound_factory::create(std::string_view id)
{ {
auto result = m_impl ? m_impl->get(id) : nullptr; auto result = m_impl ? m_impl->get(std::string{ id }) : nullptr;
if (not result) if (not result)
report_missing_compound(id); report_missing_compound(id);
return result; return result;
} }
bool compound_factory::is_known_peptide(const std::string &resName) const bool compound_factory::is_known_peptide(const std::string &res_name) const
{
return kAAMap.count(res_name) > 0;
}
bool compound_factory::is_known_base(const std::string &res_name) const
{
return kBaseMap.count(res_name) > 0;
}
/// Return whether @a res_name is a peptide
bool compound_factory::is_peptide(std::string_view res_name) const
{
bool result = is_std_peptide(res_name);
if (not result and m_impl)
{
auto compound = const_cast<compound_factory&>(*this).create(res_name);
result = compound != nullptr and compound->is_peptide();
}
return result;
}
/// Return whether @a res_name is a base
bool compound_factory::is_base(std::string_view res_name) const
{
bool result = is_std_base(res_name);
if (not result and m_impl)
{
auto compound = const_cast<compound_factory&>(*this).create(res_name);
result = compound != nullptr and compound->is_base();
}
return result;
}
/// Return whether @a res_name is one of the standard peptides
bool compound_factory::is_std_peptide(std::string_view res_name) const
{
return kAAMap.count(std::string{ res_name }) > 0;
}
/// Return whether @a res_name is one of the standard bases
bool compound_factory::is_std_base(std::string_view res_name) const
{ {
return kAAMap.count(resName) > 0; return kBaseMap.count(std::string{ res_name }) > 0;
} }
bool compound_factory::is_known_base(const std::string &resName) const /// Return whether @a res_name is a monomer (either base or peptide)
bool compound_factory::is_monomer(std::string_view res_name) const
{ {
return kBaseMap.count(resName) > 0; return is_peptide(res_name) or is_base(res_name);
} }
void compound_factory::report_missing_compound(const std::string &compound_id) void compound_factory::report_missing_compound(std::string_view compound_id)
{ {
static bool s_reported = false; static bool s_reported = false;
if (std::exchange(s_reported, true) == false) if (std::exchange(s_reported, true) == false)
......
...@@ -85,6 +85,40 @@ bool datablock::is_valid() const ...@@ -85,6 +85,40 @@ bool datablock::is_valid() const
return result; return result;
} }
bool datablock::is_valid()
{
if (m_validator == nullptr)
throw std::runtime_error("Validator not specified");
bool result = true;
for (auto &cat : *this)
result = cat.is_valid() and result;
// Add or remove the audit_conform block here.
if (result)
{
// If the dictionary declares an audit_conform category, put it in,
// but only if it does not exist already!
if (m_validator->get_validator_for_category("audit_conform") != nullptr)
{
auto &audit_conform = operator[]("audit_conform");
audit_conform.clear();
audit_conform.emplace({
// clang-format off
{ "dict_name", m_validator->name() },
{ "dict_version", m_validator->version() }
// clang-format on
});
}
}
else
erase(std::find_if(begin(), end(), [](category &cat) { return cat.name() == "audit_conform"; }), end());
return result;
}
bool datablock::validate_links() const bool datablock::validate_links() const
{ {
bool result = true; bool result = true;
...@@ -243,35 +277,6 @@ void datablock::write(std::ostream &os) const ...@@ -243,35 +277,6 @@ void datablock::write(std::ostream &os) const
if (m_validator and size() > 0) if (m_validator and size() > 0)
{ {
// If the dictionary declares an audit_conform category, put it in,
// but only if it does not exist already!
if (m_validator->get_validator_for_category("audit_conform") != nullptr)
{
auto *audit_conform = get("audit_conform");
if (audit_conform == nullptr or audit_conform->size() != 1) // There should be one entry here, I guess
audit_conform = nullptr;
else
{
// And the name and version should be filled in of course
auto &e = audit_conform->front();
if (e["dict_name"].empty() or e["dict_version"].empty())
audit_conform = nullptr;
}
if (not audit_conform)
{
category auditConform("audit_conform");
// clang-format off
auditConform.emplace({
{ "dict_name", m_validator->name() },
{ "dict_version", m_validator->version() }
});
// clang-format on
auditConform.write(os);
}
}
// base order on parent child relationships, parents first // base order on parent child relationships, parents first
cat_order_t cat_order; cat_order_t cat_order;
......
...@@ -3646,7 +3646,7 @@ void PDBFileParser::ConstructEntities() ...@@ -3646,7 +3646,7 @@ void PDBFileParser::ConstructEntities()
PDBChain::AtomRes ar{ resName, resSeq, iCode }; PDBChain::AtomRes ar{ resName, resSeq, iCode };
if ((chain.mResiduesSeen.empty() or chain.mResiduesSeen.back() != ar) and if ((chain.mResiduesSeen.empty() or chain.mResiduesSeen.back() != ar) and
(cif::compound_factory::instance().is_known_peptide(resName) or cif::compound_factory::instance().is_known_base(resName))) cif::compound_factory::instance().is_monomer(resName))
{ {
chain.mResiduesSeen.push_back(ar); chain.mResiduesSeen.push_back(ar);
} }
...@@ -3731,11 +3731,8 @@ void PDBFileParser::ConstructEntities() ...@@ -3731,11 +3731,8 @@ void PDBFileParser::ConstructEntities()
{ {
std::string resName = chain.mResiduesSeen[ix].mMonID; std::string resName = chain.mResiduesSeen[ix].mMonID;
if (cif::compound_factory::instance().is_known_peptide(resName) or if (cif::compound_factory::instance().is_monomer(resName))
cif::compound_factory::instance().is_known_base(resName))
{
chain.mTerIndex = ix + 1; chain.mTerIndex = ix + 1;
}
InsertChemComp(resName); InsertChemComp(resName);
} }
...@@ -3814,7 +3811,7 @@ void PDBFileParser::ConstructEntities() ...@@ -3814,7 +3811,7 @@ void PDBFileParser::ConstructEntities()
int residueCount = (residuePerChainCounter[chainID] += 1); int residueCount = (residuePerChainCounter[chainID] += 1);
// There appears to be a program that writes out HETATM records as ATOM records.... // There appears to be a program that writes out HETATM records as ATOM records....
if (not(cif::compound_factory::instance().is_known_peptide(resName) or cif::compound_factory::instance().is_known_base(resName)) or if (not cif::compound_factory::instance().is_monomer(resName) or
terminatedChains.count(chainID) or terminatedChains.count(chainID) or
(chain.mTerIndex > 0 and residueCount >= chain.mTerIndex)) (chain.mTerIndex > 0 and residueCount >= chain.mTerIndex))
{ {
......
...@@ -145,12 +145,16 @@ bool is_valid_pdbx_file(const file &file, std::string_view dictionary, std::erro ...@@ -145,12 +145,16 @@ bool is_valid_pdbx_file(const file &file, std::string_view dictionary, std::erro
last_seq_id = *seq_id; last_seq_id = *seq_id;
auto comp_id = r.get<std::string>("label_comp_id"); auto comp_id = r.get<std::string>("label_comp_id");
if (not cf.is_known_peptide(comp_id)) if (not cf.is_monomer(comp_id))
continue; continue;
auto p = pdbx_poly_seq_scheme.find(get_parents_condition(validator, r, pdbx_poly_seq_scheme)); auto p = pdbx_poly_seq_scheme.find(get_parents_condition(validator, r, pdbx_poly_seq_scheme));
if (p.size() != 1) if (p.size() != 1)
throw std::runtime_error("For each residue in atom_site that is a residue in a polymer there should be exactly one pdbx_poly_seq_scheme record"); {
if (cif::VERBOSE > 0)
std::clog << "In atom_site record: " << r["id"].text() << '\n';
throw std::runtime_error("For each monomer in atom_site there should be exactly one pdbx_poly_seq_scheme record");
}
} }
auto &entity = db["entity"]; auto &entity = db["entity"];
...@@ -244,9 +248,9 @@ bool is_valid_pdbx_file(const file &file, std::string_view dictionary, std::erro ...@@ -244,9 +248,9 @@ bool is_valid_pdbx_file(const file &file, std::string_view dictionary, std::erro
for (auto comp_id : comp_ids) for (auto comp_id : comp_ids)
{ {
std::string letter; std::string letter;
if (cf.is_known_base(comp_id)) if (compound_factory::kBaseMap.contains(comp_id))
letter = compound_factory::kBaseMap.at(comp_id); letter = compound_factory::kBaseMap.at(comp_id);
else if (cf.is_known_peptide(comp_id)) else if (compound_factory::kAAMap.contains(comp_id))
letter = compound_factory::kAAMap.at(comp_id); letter = compound_factory::kAAMap.at(comp_id);
else else
{ {
...@@ -304,7 +308,6 @@ bool is_valid_pdbx_file(const file &file, std::string_view dictionary, std::erro ...@@ -304,7 +308,6 @@ bool is_valid_pdbx_file(const file &file, std::string_view dictionary, std::erro
if (not seq_match(true, seq_can->begin(), seq_can->end())) if (not seq_match(true, seq_can->begin(), seq_can->end()))
throw std::runtime_error("Canonical sequences do not match for entity " + entity_id); throw std::runtime_error("Canonical sequences do not match for entity " + entity_id);
} }
} }
result = true; result = true;
......
...@@ -49,6 +49,25 @@ using std::regex; ...@@ -49,6 +49,25 @@ using std::regex;
namespace cif namespace cif
{ {
validation_exception::validation_exception(std::error_code ec)
: runtime_error(ec.message())
{
}
validation_exception::validation_exception(std::error_code ec, std::string_view category)
: runtime_error(
(std::ostringstream{} << ec.message() << "; category: " << std::quoted(category)).str())
{
}
validation_exception::validation_exception(std::error_code ec, std::string_view category, std::string_view item)
: runtime_error(
(std::ostringstream{} << ec.message() << "; category: " << std::quoted(category) << "; item: " << std::quoted(item)).str())
{
}
// --------------------------------------------------------------------
struct regex_impl : public regex struct regex_impl : public regex
{ {
regex_impl(std::string_view rx) regex_impl(std::string_view rx)
...@@ -380,18 +399,10 @@ std::vector<const link_validator *> validator::get_links_for_child(std::string_v ...@@ -380,18 +399,10 @@ std::vector<const link_validator *> validator::get_links_for_child(std::string_v
return result; return result;
} }
// void validator::report_error(const std::string &msg, bool fatal) const
// {
// if (m_strict or fatal)
// throw validation_error(msg);
// else if (VERBOSE > 0)
// std::cerr << msg << '\n';
// }
void validator::report_error(std::error_code ec, bool fatal) const void validator::report_error(std::error_code ec, bool fatal) const
{ {
if (m_strict or fatal) if (m_strict or fatal)
throw std::system_error(ec); throw validation_exception(ec);
else else
std::cerr << ec.message() << '\n'; std::cerr << ec.message() << '\n';
} }
...@@ -399,15 +410,14 @@ void validator::report_error(std::error_code ec, bool fatal) const ...@@ -399,15 +410,14 @@ void validator::report_error(std::error_code ec, bool fatal) const
void validator::report_error(std::error_code ec, std::string_view category, void validator::report_error(std::error_code ec, std::string_view category,
std::string_view item, bool fatal) const std::string_view item, bool fatal) const
{ {
std::ostringstream os; auto ex = item.empty() ?
os << "category: "<< category; validation_exception(ec, category) :
if (not item.empty()) validation_exception(ec, category, item);
os << "; item: " << item;
if (m_strict or fatal) if (m_strict or fatal)
throw std::system_error(ec, os.str()); throw ex;
else else
std::cerr << ec.message() << ": " << os.str() << '\n'; std::cerr << ex.what() << '\n';
} }
// -------------------------------------------------------------------- // --------------------------------------------------------------------
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2024 NKI/AVL, Netherlands Cancer Institute
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test-main.hpp"
#include <cif++.hpp>
#include <catch2/catch.hpp>
#include <iostream>
#include <fstream>
TEST_CASE("reconstruct")
{
cif::compound_factory::instance().push_dictionary(gTestDir / "REA.cif");
for (std::filesystem::directory_iterator i(gTestDir / "reconstruct"); i != std::filesystem::directory_iterator{}; ++i)
{
std::cout << i->path() << '\n';
cif::file f(i->path());
std::error_code ec;
CHECK_FALSE(cif::pdb::is_valid_pdbx_file(f, ec));
CHECK(ec != std::errc{});
CHECK(cif::pdb::reconstruct_pdbx(f));
}
}
\ No newline at end of file
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