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()