diff --git a/modules/bindings/pymod/CMakeLists.txt b/modules/bindings/pymod/CMakeLists.txt
index 0e194a0ebe6b5480258d9fdff253f35be4685c63..5dd7a1cc99bf9d75386cdde85e5c2da2ebe07bcc 100644
--- a/modules/bindings/pymod/CMakeLists.txt
+++ b/modules/bindings/pymod/CMakeLists.txt
@@ -1 +1 @@
-pymod(NAME bindings PY __init__.py lga.py hbplus.py msms.py)
+pymod(NAME bindings PY __init__.py lga.py hbplus.py msms.py tmtools.py)
diff --git a/modules/bindings/pymod/tmtools.py b/modules/bindings/pymod/tmtools.py
new file mode 100644
index 0000000000000000000000000000000000000000..76abc5324b89af06d0c0d917960b1efc55d0b9ea
--- /dev/null
+++ b/modules/bindings/pymod/tmtools.py
@@ -0,0 +1,123 @@
+#------------------------------------------------------------------------------
+# This file is part of the OpenStructure project <www.openstructure.org>
+#
+# Copyright (C) 2008-2009 by the OpenStructure authors
+#
+# This library is free software; you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation; either version 3.0 of the License, or (at your option)
+# any later version.
+# This library is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this library; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+#------------------------------------------------------------------------------
+"""
+Wrappers for the tmalign and tmscore utilities.
+
+References:
+
+tmscore: Yang Zhang and Jeffrey Skolnick, Proteins 2004 57: 702-710 
+tmalign: Y. Zhang and J. Skolnick, Nucl. Acids Res. 2005 33, 2302-9 
+
+
+Authors: Pascal Benkert, Marco Biasini
+"""
+
+import subprocess, os, tempfile
+from ost import settings, io, geom
+
+def _SetupFiles(models):
+  # create temporary directory
+  tmp_dir_name=tempfile.mkdtemp()
+  for index, model in enumerate(models):
+    io.SavePDB(model, os.path.join(tmp_dir_name, 'model%02d.pdb' % (index+1)))
+  return tmp_dir_name
+
+def _CleanupFiles(dir_name):
+  import shutil
+  shutil.rmtree(dir_name)
+  
+def _ParseTmAlign(lines):
+  tf1=[float(i.strip()) for i in lines[15].split()]
+  tf2=[float(i.strip()) for i in lines[16].split()]
+  tf3=[float(i.strip()) for i in lines[17].split()]
+  rot=geom.Mat3(tf1[2], tf1[3], tf1[4], tf2[2], tf2[3],
+                tf2[4], tf3[2], tf3[3], tf3[4])
+  tf=geom.Mat4(rot)
+  tf.PasteTranslation(geom.Vec3(tf1[1], tf2[1], tf3[1]))
+  return tf
+
+def _RunTmAlign(tmalign, tmp_dir):
+  tmalign_path=settings.Locate('tmalign', explicit_file_name=tmalign)
+  model1_filename=os.path.join(tmp_dir, 'model01.pdb')
+  model2_filename=os.path.join(tmp_dir, 'model02.pdb')  
+  command="%s '%s' '%s'" %(tmalign_path, model1_filename, model2_filename)
+  ps=subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
+  lines=ps.stdout.readlines()
+  if (len(lines))<22:
+    raise RuntimeError("tmalign superposition failed")
+  return _ParseTmAlign(lines)
+
+class TMScoreResult:
+  def __init__(self, rmsd_common, tm_score, max_sub, 
+               gdt_ts, gdt_ha, rmsd_below_five, transform):
+    self.rmsd_common=rmsd_common
+    self.tm_score=tm_score    
+    self.max_sub=max_sub
+    self.gdt_ts=gdt_ts
+    self.gdt_ha=gdt_ha
+    self.rmsd_below_five=rmsd_below_five
+    self.transform=transform
+    
+def _ParseTmScore(lines):
+  tf1=[float(i.strip()) for i in lines[23].split()]
+  tf2=[float(i.strip()) for i in lines[24].split()]
+  tf3=[float(i.strip()) for i in lines[25].split()]
+  rot=geom.Mat3(tf1[2], tf1[3], tf1[4], tf2[2], tf2[3],
+                  tf2[4], tf3[2], tf3[3], tf3[4])
+  tf=geom.Mat4(rot)
+  tf.PasteTranslation(geom.Vec3(tf1[1], tf2[1], tf3[1]))
+  result=TMScoreResult(float(lines[14].split()[-1].strip()),
+                       float(lines[16].split()[2].strip()),
+                       float(lines[17].split()[1].strip()),
+                       float(lines[18].split()[1].strip()),
+                       float(lines[19].split()[1].strip()),
+                       float(lines[27].split()[-1].strip()),
+                       tf)
+  return result
+
+
+def _RunTmScore(tmscore, tmp_dir):
+  tmscore_path=settings.Locate('tmscore', explicit_file_name=tmscore)
+  model1_filename=os.path.join(tmp_dir, 'model01.pdb')
+  model2_filename=os.path.join(tmp_dir, 'model02.pdb')  
+  command="%s '%s' '%s'" %(tmscore_path, model1_filename, model2_filename)
+  ps=subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
+  lines=ps.stdout.readlines()
+  if (len(lines))<22:
+    raise RuntimeError("tmscore superposition failed")
+  return _ParseTmScore(lines)
+
+def TMAlign(model1, model2, tmalign=None):
+  """
+  Run tmalign on two protein structures
+  """
+  tmp_dir_name=_SetupFiles((model1, model2))
+  tf=_RunTmAlign(tmalign, tmp_dir_name)
+  model1.handle.RequestXCSEditor().ApplyTransform(tf)
+  _CleanupFiles(tmp_dir_name)
+
+def TMScore(model1, model2, tmscore=None):
+  """
+  Run tmscore on two protein structures
+  """
+  tmp_dir_name=_SetupFiles((model1, model2))
+  result=_RunTmScore(tmscore, tmp_dir_name)
+  model1.handle.RequestXCSEditor().ApplyTransform(result.transform)  
+  _CleanupFiles(tmp_dir_name)
+  return result
\ No newline at end of file