diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 9189aecece5345a60ec850332af0fca826e14603..45ebdf60c4dcd6fdac658c24ad70a10190623430 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,3 +1,13 @@ +Changes in Release 1.7.1 +-------------------------------------------------------------------------------- + + * Fixed an issue that could cause the star format parser (mmCIF, chemical + components dictionary) to enter an infinite loop + * Chemical components dictionary was extended by new chemical classes + introduced by PDB + * Fixed unit tests + * Improved documentation + Changes in Release 1.7 -------------------------------------------------------------------------------- diff --git a/CMakeLists.txt b/CMakeLists.txt index 2f582069ba52a1b79e281c8866d6f591c5f1942e..2cf4c283a4cbfd59833a4d76837da48948dbe9f1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ project(OpenStructure CXX C) set (CMAKE_EXPORT_COMPILE_COMMANDS 1) set (OST_VERSION_MAJOR 1) set (OST_VERSION_MINOR 7) -set (OST_VERSION_PATCH 0) +set (OST_VERSION_PATCH 1) set (OST_VERSION_STRING ${OST_VERSION_MAJOR}.${OST_VERSION_MINOR}.${OST_VERSION_PATCH} ) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/cmake_support) include(OST) diff --git a/modules/conop/doc/cleanup.rst b/modules/conop/doc/cleanup.rst index 35b20e5705b248a995ec61c5e06604c53df0767f..a7a49bdf6d1463fdead7fd9ad02180be4ea0bcbe 100644 --- a/modules/conop/doc/cleanup.rst +++ b/modules/conop/doc/cleanup.rst @@ -1,7 +1,7 @@ :mod:`conop.cleanup <ost.conop.cleanup>` -- Sanitize structures ================================================================================ -.. module:: ost.conop.ceanup +.. module:: ost.conop.cleanup :synopsis: Contains functions to sanitize (cleanup) structures by using information from the compound library. diff --git a/modules/io/src/mol/chemdict_parser.cc b/modules/io/src/mol/chemdict_parser.cc index 47f7f6f2d369a9e446a4929ec6a914fa6aa179d4..cf97f5e23d933c68a7fa6e5419027ae5b24cf534 100644 --- a/modules/io/src/mol/chemdict_parser.cc +++ b/modules/io/src/mol/chemdict_parser.cc @@ -195,17 +195,18 @@ void ChemdictParser::InitTypeMap() tm_["DNA LINKING"]=mol::ChemClass(mol::ChemClass::DNA_LINKING); tm_["RNA LINKING"]=mol::ChemClass(mol::ChemClass::RNA_LINKING); tm_["L-DNA LINKING"]=mol::ChemClass(mol::ChemClass::DNA_LINKING); - tm_["L-RNA LINKING"]=mol::ChemClass(mol::ChemClass::RNA_LINKING); + tm_["L-RNA LINKING"]=mol::ChemClass(mol::ChemClass::RNA_LINKING); tm_["R-DNA LINKING"]=mol::ChemClass(mol::ChemClass::DNA_LINKING); - tm_["R-RNA LINKING"]=mol::ChemClass(mol::ChemClass::RNA_LINKING); + tm_["R-RNA LINKING"]=mol::ChemClass(mol::ChemClass::RNA_LINKING); tm_["DNA OH 3 PRIME TERMINUS"]=mol::ChemClass(mol::ChemClass::DNA_LINKING); + tm_["DNA OH 5 PRIME TERMINUS"]=mol::ChemClass(mol::ChemClass::DNA_LINKING); tm_["PEPTIDE-LIKE"]=mol::ChemClass(mol::ChemClass::PEPTIDE_LINKING); tm_["PEPTIDE LINKING"]=mol::ChemClass(mol::ChemClass::PEPTIDE_LINKING); - tm_["PEPTIDE-LINKING"]=mol::ChemClass(mol::ChemClass::PEPTIDE_LINKING); + tm_["PEPTIDE-LINKING"]=mol::ChemClass(mol::ChemClass::PEPTIDE_LINKING); tm_["NON-POLYMER"]=mol::ChemClass(mol::ChemClass::NON_POLYMER); tm_["RNA OH 3 PRIME TERMINUS"]=mol::ChemClass(mol::ChemClass::RNA_LINKING); tm_["RNA OH 5 PRIME TERMINUS"]=mol::ChemClass(mol::ChemClass::RNA_LINKING); - tm_["?"]=mol::ChemClass(mol::ChemClass::UNKNOWN); + tm_["?"]=mol::ChemClass(mol::ChemClass::UNKNOWN); tm_["WATER"]=mol::ChemClass(mol::ChemClass::WATER); } diff --git a/modules/io/src/mol/star_parser.cc b/modules/io/src/mol/star_parser.cc index 80043259b4df5fdf34ee81de6bf471696d03bc5a..214eb626c9f743a1cbbb218bede0ad7f795b2f73 100644 --- a/modules/io/src/mol/star_parser.cc +++ b/modules/io/src/mol/star_parser.cc @@ -550,11 +550,15 @@ void StarParser::Parse() case 'd': if (tline.length()>=5 && StringRef("data_", 5)==tline.substr(0, 5)) { this->ParseData(); + } else { + throw IOException("Missing 'data_' control structure"); } break; case 'g': if (tline.length()>=7 && StringRef("global_", 7)==tline.substr(0, 7)) { this->ParseGlobal(); + } else { + throw IOException("Missing 'global_' control structure"); } break; case '#': diff --git a/modules/io/tests/test_star_parser.cc b/modules/io/tests/test_star_parser.cc index 6ff217b748c123770f789a2168d540be3f1ef94d..c4e40fdbda137d74293282a592884fb5aa7e8305 100644 --- a/modules/io/tests/test_star_parser.cc +++ b/modules/io/tests/test_star_parser.cc @@ -389,6 +389,20 @@ BOOST_AUTO_TEST_CASE(star_items_as_row) BOOST_TEST_MESSAGE(" done."); } +BOOST_AUTO_TEST_CASE(star_broken_data) +{ + std::ifstream s("testfiles/broken_data.cif"); + LoopTestParser star_p(s); + BOOST_CHECK_THROW(star_p.Parse(), IOException); +} + +BOOST_AUTO_TEST_CASE(star_broken_global) +{ + std::ifstream s("testfiles/broken_global.cif"); + LoopTestParser star_p(s); + BOOST_CHECK_THROW(star_p.Parse(), IOException); +} + BOOST_AUTO_TEST_CASE(star_missing_data) { std::ifstream s("testfiles/missing_data.cif"); diff --git a/modules/io/tests/testfiles/broken_data.cif b/modules/io/tests/testfiles/broken_data.cif new file mode 100644 index 0000000000000000000000000000000000000000..2ae242255c2bd8c6e952ffee6d1815ee01f6335a --- /dev/null +++ b/modules/io/tests/testfiles/broken_data.cif @@ -0,0 +1 @@ +d lines starting with a 'd' kicked the parser into an infinite loop. diff --git a/modules/io/tests/testfiles/broken_global.cif b/modules/io/tests/testfiles/broken_global.cif new file mode 100644 index 0000000000000000000000000000000000000000..0f340e0befe0077229b53b121979181ec3c890fc --- /dev/null +++ b/modules/io/tests/testfiles/broken_global.cif @@ -0,0 +1 @@ +g lines starting with a 'g' kicked the parser into an infinite loop. diff --git a/modules/mol/alg/pymod/qsscoring.py b/modules/mol/alg/pymod/qsscoring.py index 42c073f41eccfb77f44d5d89f49ca52169496a19..16635d7025e330345dfc20109cf19fd63ffc4257 100644 --- a/modules/mol/alg/pymod/qsscoring.py +++ b/modules/mol/alg/pymod/qsscoring.py @@ -56,6 +56,8 @@ class QSscorer: qs_scorer = qsscoring.QSscorer(ent_1, ent_2) ost.LogScript('QSscore:', str(qs_scorer.global_score)) ost.LogScript('Chain mapping used:', str(qs_scorer.chain_mapping)) + # commonly you want the QS global score as output + qs_score = qs_scorer.global_score except qsscoring.QSscoreError as ex: # default handling: report failure and set score to 0 ost.LogError('QSscore failed:', str(ex)) diff --git a/modules/mol/base/tests/CMakeLists.txt b/modules/mol/base/tests/CMakeLists.txt index 1aa275c1adca3bbc7afed1f34b4b3518fcfa6593..0f756cd3c159d204d93c4653e513be0599ca5ac8 100644 --- a/modules/mol/base/tests/CMakeLists.txt +++ b/modules/mol/base/tests/CMakeLists.txt @@ -17,7 +17,7 @@ set(OST_MOL_BASE_UNIT_TESTS ) if (USE_NUMPY) - set(OST_MOST_BASE_UNIT_TESTS "${OST_MOST_BASE_UNIT_TESTS}" test_numpy.py) + list(APPEND OST_MOL_BASE_UNIT_TESTS test_numpy.py) endif (USE_NUMPY) ost_unittest(MODULE mol SOURCES "${OST_MOL_BASE_UNIT_TESTS}") diff --git a/modules/mol/base/tests/test_numpy.py b/modules/mol/base/tests/test_numpy.py index 217ed89dd7adb6380b6fea22719e49f310b2c2cb..27061a234cc96d72ceaeec28ffad6ab18ca44d0a 100644 --- a/modules/mol/base/tests/test_numpy.py +++ b/modules/mol/base/tests/test_numpy.py @@ -5,6 +5,7 @@ if __name__== '__main__': sys.path.insert(0,"../../../../stage/lib/openstructure/") import ost +from ost import geom, mol if ost.WITH_NUMPY: has_numpy=True @@ -16,10 +17,10 @@ else: has_numpy=False def v2v(v): - return ost.geom.Vec3(float(v[0]),float(v[1]),float(v[2])) + return geom.Vec3(float(v[0]),float(v[1]),float(v[2])) def dd(v1,v2): - return ost.geom.Distance(v1,v2)<1e-8 + return geom.Distance(v1,v2)<1e-8 class TestNumpy(unittest.TestCase): def setUp(self): @@ -28,46 +29,46 @@ class TestNumpy(unittest.TestCase): def test_(self): if not has_numpy: return - entity=ost.mol.CreateEntity() + entity=mol.CreateEntity() ed=entity.EditXCS() ch=ed.InsertChain("X") re=ed.AppendResidue(ch,"ALA") - a0=ed.InsertAtom(re,"A",ost.geom.Vec3(0,0,0)) + a0=ed.InsertAtom(re,"A",geom.Vec3(0,0,0)) self.assertEqual(a0.GetIndex(),0) - a1=ed.InsertAtom(re,"B",ost.geom.Vec3(1,0,0)) + a1=ed.InsertAtom(re,"B",geom.Vec3(1,0,0)) self.assertEqual(a1.GetIndex(),1) - a2=ed.InsertAtom(re,"C",ost.geom.Vec3(2,0,0)) + a2=ed.InsertAtom(re,"C",geom.Vec3(2,0,0)) self.assertEqual(a2.GetIndex(),2) - a3=ed.InsertAtom(re,"D",ost.geom.Vec3(3,0,0)) + a3=ed.InsertAtom(re,"D",geom.Vec3(3,0,0)) self.assertEqual(a3.GetIndex(),3) - self.assertTrue(dd(a0.pos,ost.geom.Vec3(0,0,0))) - self.assertTrue(dd(a1.pos,ost.geom.Vec3(1,0,0))) - self.assertTrue(dd(a2.pos,ost.geom.Vec3(2,0,0))) - self.assertTrue(dd(a3.pos,ost.geom.Vec3(3,0,0))) + self.assertTrue(dd(a0.pos,geom.Vec3(0,0,0))) + self.assertTrue(dd(a1.pos,geom.Vec3(1,0,0))) + self.assertTrue(dd(a2.pos,geom.Vec3(2,0,0))) + self.assertTrue(dd(a3.pos,geom.Vec3(3,0,0))) ed.SetAtomTransformedPos(entity.GetAtomList(), numpy.array([[0,1,0],[0,2,0],[0,3,0],[0,4,0]], dtype=numpy.float32)) - self.assertTrue(dd(a0.pos,ost.geom.Vec3(0,1,0))) - self.assertTrue(dd(a1.pos,ost.geom.Vec3(0,2,0))) - self.assertTrue(dd(a2.pos,ost.geom.Vec3(0,3,0))) - self.assertTrue(dd(a3.pos,ost.geom.Vec3(0,4,0))) + self.assertTrue(dd(a0.pos,geom.Vec3(0,1,0))) + self.assertTrue(dd(a1.pos,geom.Vec3(0,2,0))) + self.assertTrue(dd(a2.pos,geom.Vec3(0,3,0))) + self.assertTrue(dd(a3.pos,geom.Vec3(0,4,0))) na=entity.positions - self.assertTrue(dd(v2v(na[0]),ost.geom.Vec3(0,1,0))) - self.assertTrue(dd(v2v(na[1]),ost.geom.Vec3(0,2,0))) - self.assertTrue(dd(v2v(na[2]),ost.geom.Vec3(0,3,0))) - self.assertTrue(dd(v2v(na[3]),ost.geom.Vec3(0,4,0))) + self.assertTrue(dd(v2v(na[0]),geom.Vec3(0,1,0))) + self.assertTrue(dd(v2v(na[1]),geom.Vec3(0,2,0))) + self.assertTrue(dd(v2v(na[2]),geom.Vec3(0,3,0))) + self.assertTrue(dd(v2v(na[3]),geom.Vec3(0,4,0))) ed.SetAtomTransformedPos([3,99,2], numpy.array([[0,0,-3],[-1,-1,-1],[0,0,-2]], dtype=numpy.float32)) - self.assertTrue(dd(a0.pos,ost.geom.Vec3(0,1,0))) - self.assertTrue(dd(a1.pos,ost.geom.Vec3(0,2,0))) - self.assertTrue(dd(a2.pos,ost.geom.Vec3(0,0,-2))) - self.assertTrue(dd(a3.pos,ost.geom.Vec3(0,0,-3))) + self.assertTrue(dd(a0.pos,geom.Vec3(0,1,0))) + self.assertTrue(dd(a1.pos,geom.Vec3(0,2,0))) + self.assertTrue(dd(a2.pos,geom.Vec3(0,0,-2))) + self.assertTrue(dd(a3.pos,geom.Vec3(0,0,-3))) if __name__== '__main__': unittest.main()