IMP  2.0.0
The Integrative Modeling Platform
test/__init__.py
1 # This file was automatically generated by SWIG (http://www.swig.org).
2 # Version 2.0.8
3 #
4 # Do not make changes to this file unless you know what you are doing--modify
5 # the SWIG interface file instead.
6 
7 
8 
9 from sys import version_info
10 if version_info >= (2,6,0):
11  def swig_import_helper():
12  from os.path import dirname
13  import imp
14  fp = None
15  try:
16  fp, pathname, description = imp.find_module('_IMP_test', [dirname(__file__)])
17  except ImportError:
18  import _IMP_test
19  return _IMP_test
20  if fp is not None:
21  try:
22  _mod = imp.load_module('_IMP_test', fp, pathname, description)
23  finally:
24  fp.close()
25  return _mod
26  _IMP_test = swig_import_helper()
27  del swig_import_helper
28 else:
29  import _IMP_test
30 del version_info
31 try:
32  _swig_property = property
33 except NameError:
34  pass # Python < 2.2 doesn't have 'property'.
35 def _swig_setattr_nondynamic(self,class_type,name,value,static=1):
36  if (name == "thisown"): return self.this.own(value)
37  if (name == "this"):
38  if type(value).__name__ == 'SwigPyObject':
39  self.__dict__[name] = value
40  return
41  method = class_type.__swig_setmethods__.get(name,None)
42  if method: return method(self,value)
43  if (not static):
44  self.__dict__[name] = value
45  else:
46  raise AttributeError("You cannot add attributes to %s" % self)
47 
48 def _swig_setattr(self,class_type,name,value):
49  return _swig_setattr_nondynamic(self,class_type,name,value,0)
50 
51 def _swig_getattr(self,class_type,name):
52  if (name == "thisown"): return self.this.own()
53  method = class_type.__swig_getmethods__.get(name,None)
54  if method: return method(self)
55  raise AttributeError(name)
56 
57 def _swig_repr(self):
58  try: strthis = "proxy of " + self.this.__repr__()
59  except: strthis = ""
60  return "<%s.%s; %s >" % (self.__class__.__module__, self.__class__.__name__, strthis,)
61 
62 try:
63  _object = object
64  _newclass = 1
65 except AttributeError:
66  class _object : pass
67  _newclass = 0
68 
69 
70 try:
71  import weakref
72  weakref_proxy = weakref.proxy
73 except:
74  weakref_proxy = lambda x: x
75 
76 
77 class IMP_TEST_SwigPyIterator(_object):
78  """Proxy of C++ swig::IMP_TEST_SwigPyIterator class"""
79  __swig_setmethods__ = {}
80  __setattr__ = lambda self, name, value: _swig_setattr(self, IMP_TEST_SwigPyIterator, name, value)
81  __swig_getmethods__ = {}
82  __getattr__ = lambda self, name: _swig_getattr(self, IMP_TEST_SwigPyIterator, name)
83  def __init__(self, *args, **kwargs): raise AttributeError("No constructor defined - class is abstract")
84  __repr__ = _swig_repr
85  __swig_destroy__ = _IMP_test.delete_IMP_TEST_SwigPyIterator
86  __del__ = lambda self : None;
87  def value(self):
88  """value(IMP_TEST_SwigPyIterator self) -> PyObject *"""
89  return _IMP_test.IMP_TEST_SwigPyIterator_value(self)
90 
91  def incr(self, n=1):
92  """
93  incr(IMP_TEST_SwigPyIterator self, size_t n=1) -> IMP_TEST_SwigPyIterator
94  incr(IMP_TEST_SwigPyIterator self) -> IMP_TEST_SwigPyIterator
95  """
96  return _IMP_test.IMP_TEST_SwigPyIterator_incr(self, n)
97 
98  def decr(self, n=1):
99  """
100  decr(IMP_TEST_SwigPyIterator self, size_t n=1) -> IMP_TEST_SwigPyIterator
101  decr(IMP_TEST_SwigPyIterator self) -> IMP_TEST_SwigPyIterator
102  """
103  return _IMP_test.IMP_TEST_SwigPyIterator_decr(self, n)
104 
105  def distance(self, *args):
106  """distance(IMP_TEST_SwigPyIterator self, IMP_TEST_SwigPyIterator x) -> ptrdiff_t"""
107  return _IMP_test.IMP_TEST_SwigPyIterator_distance(self, *args)
108 
109  def equal(self, *args):
110  """equal(IMP_TEST_SwigPyIterator self, IMP_TEST_SwigPyIterator x) -> bool"""
111  return _IMP_test.IMP_TEST_SwigPyIterator_equal(self, *args)
112 
113  def copy(self):
114  """copy(IMP_TEST_SwigPyIterator self) -> IMP_TEST_SwigPyIterator"""
115  return _IMP_test.IMP_TEST_SwigPyIterator_copy(self)
116 
117  def next(self):
118  """next(IMP_TEST_SwigPyIterator self) -> PyObject *"""
119  return _IMP_test.IMP_TEST_SwigPyIterator_next(self)
120 
121  def __next__(self):
122  """__next__(IMP_TEST_SwigPyIterator self) -> PyObject *"""
123  return _IMP_test.IMP_TEST_SwigPyIterator___next__(self)
124 
125  def previous(self):
126  """previous(IMP_TEST_SwigPyIterator self) -> PyObject *"""
127  return _IMP_test.IMP_TEST_SwigPyIterator_previous(self)
128 
129  def advance(self, *args):
130  """advance(IMP_TEST_SwigPyIterator self, ptrdiff_t n) -> IMP_TEST_SwigPyIterator"""
131  return _IMP_test.IMP_TEST_SwigPyIterator_advance(self, *args)
132 
133  def __eq__(self, *args):
134  """__eq__(IMP_TEST_SwigPyIterator self, IMP_TEST_SwigPyIterator x) -> bool"""
135  return _IMP_test.IMP_TEST_SwigPyIterator___eq__(self, *args)
136 
137  def __ne__(self, *args):
138  """__ne__(IMP_TEST_SwigPyIterator self, IMP_TEST_SwigPyIterator x) -> bool"""
139  return _IMP_test.IMP_TEST_SwigPyIterator___ne__(self, *args)
140 
141  def __iadd__(self, *args):
142  """__iadd__(IMP_TEST_SwigPyIterator self, ptrdiff_t n) -> IMP_TEST_SwigPyIterator"""
143  return _IMP_test.IMP_TEST_SwigPyIterator___iadd__(self, *args)
144 
145  def __isub__(self, *args):
146  """__isub__(IMP_TEST_SwigPyIterator self, ptrdiff_t n) -> IMP_TEST_SwigPyIterator"""
147  return _IMP_test.IMP_TEST_SwigPyIterator___isub__(self, *args)
148 
149  def __add__(self, *args):
150  """__add__(IMP_TEST_SwigPyIterator self, ptrdiff_t n) -> IMP_TEST_SwigPyIterator"""
151  return _IMP_test.IMP_TEST_SwigPyIterator___add__(self, *args)
152 
153  def __sub__(self, *args):
154  """
155  __sub__(IMP_TEST_SwigPyIterator self, ptrdiff_t n) -> IMP_TEST_SwigPyIterator
156  __sub__(IMP_TEST_SwigPyIterator self, IMP_TEST_SwigPyIterator x) -> ptrdiff_t
157  """
158  return _IMP_test.IMP_TEST_SwigPyIterator___sub__(self, *args)
159 
160  def __iter__(self): return self
161 IMP_TEST_SwigPyIterator_swigregister = _IMP_test.IMP_TEST_SwigPyIterator_swigregister
162 IMP_TEST_SwigPyIterator_swigregister(IMP_TEST_SwigPyIterator)
163 
164 _value_types=[]
165 _object_types=[]
166 _raii_types=[]
167 _plural_types=[]
168 
169 IMP_HAS_DEPRECATED = _IMP_test.IMP_HAS_DEPRECATED
170 IMP_DEBUG = _IMP_test.IMP_DEBUG
171 IMP_RELEASE = _IMP_test.IMP_RELEASE
172 IMP_SILENT = _IMP_test.IMP_SILENT
173 IMP_PROGRESS = _IMP_test.IMP_PROGRESS
174 IMP_TERSE = _IMP_test.IMP_TERSE
175 IMP_VERBOSE = _IMP_test.IMP_VERBOSE
176 IMP_NONE = _IMP_test.IMP_NONE
177 IMP_USAGE = _IMP_test.IMP_USAGE
178 IMP_INTERNAL = _IMP_test.IMP_INTERNAL
179 IMP_COMPILER_HAS_AUTO = _IMP_test.IMP_COMPILER_HAS_AUTO
180 IMP_COMPILER_HAS_DEBUG_VECTOR = _IMP_test.IMP_COMPILER_HAS_DEBUG_VECTOR
181 IMP_COMPILER_HAS_NULLPTR = _IMP_test.IMP_COMPILER_HAS_NULLPTR
182 IMP_BASE_HAS_BOOST_RANDOM = _IMP_test.IMP_BASE_HAS_BOOST_RANDOM
183 IMP_BASE_HAS_GPERFTOOLS = _IMP_test.IMP_BASE_HAS_GPERFTOOLS
184 IMP_BASE_HAS_LOG4CXX = _IMP_test.IMP_BASE_HAS_LOG4CXX
185 IMP_BASE_HAS_TCMALLOC_HEAPCHECKER = _IMP_test.IMP_BASE_HAS_TCMALLOC_HEAPCHECKER
186 IMP_BASE_HAS_TCMALLOC_HEAPPROFILER = _IMP_test.IMP_BASE_HAS_TCMALLOC_HEAPPROFILER
187 import sys
188 class _DirectorObjects(object):
189  """@internal Simple class to keep references to director objects
190  to prevent premature deletion."""
191  def __init__(self):
192  self._objects = []
193  def register(self, obj):
194  """Take a reference to a director object; will only work for
195  refcounted C++ classes"""
196  if hasattr(obj, 'get_ref_count'):
197  self._objects.append(obj)
198  def cleanup(self):
199  """Only drop our reference and allow cleanup by Python if no other
200  Python references exist (we hold 3 references: one in self._objects,
201  one in x, and one in the argument list for getrefcount) *and* no
202  other C++ references exist (the Python object always holds one)"""
203  objs = [x for x in self._objects if sys.getrefcount(x) > 3 \
204  or x.get_ref_count() > 1]
205 
206 
207  self._objects = objs
208  def get_object_count(self):
209  """Get number of director objects (useful for testing only)"""
210  return len(self._objects)
211 _director_objects = _DirectorObjects()
212 
213 DEFAULT_CHECK = _IMP_test.DEFAULT_CHECK
214 NONE = _IMP_test.NONE
215 USAGE = _IMP_test.USAGE
216 USAGE_AND_INTERNAL = _IMP_test.USAGE_AND_INTERNAL
217 
218 def set_check_level(*args):
219  """set_check_level(IMP::base::CheckLevel tf)"""
220  return _IMP_test.set_check_level(*args)
221 
222 def get_check_level():
223  """get_check_level() -> IMP::base::CheckLevel"""
224  return _IMP_test.get_check_level()
225 class _ostream(_object):
226  """Proxy of C++ std::ostream class"""
227  __swig_setmethods__ = {}
228  __setattr__ = lambda self, name, value: _swig_setattr(self, _ostream, name, value)
229  __swig_getmethods__ = {}
230  __getattr__ = lambda self, name: _swig_getattr(self, _ostream, name)
231  def __init__(self, *args, **kwargs): raise AttributeError("No constructor defined")
232  __repr__ = _swig_repr
233  def write(self, *args):
234  """write(_ostream self, char const * osa_buf)"""
235  return _IMP_test._ostream_write(self, *args)
236 
237 _ostream_swigregister = _IMP_test._ostream_swigregister
238 _ostream_swigregister(_ostream)
239 
240 IMP_COMPILER_HAS_OVERRIDE = _IMP_test.IMP_COMPILER_HAS_OVERRIDE
241 IMP_COMPILER_HAS_FINAL = _IMP_test.IMP_COMPILER_HAS_FINAL
242 import IMP.base
243 IMP_TEST_HAS_BOOST_FILESYSTEM = _IMP_test.IMP_TEST_HAS_BOOST_FILESYSTEM
244 IMP_TEST_HAS_BOOST_PROGRAMOPTIONS = _IMP_test.IMP_TEST_HAS_BOOST_PROGRAMOPTIONS
245 IMP_TEST_HAS_BOOST_RANDOM = _IMP_test.IMP_TEST_HAS_BOOST_RANDOM
246 IMP_TEST_HAS_BOOST_SYSTEM = _IMP_test.IMP_TEST_HAS_BOOST_SYSTEM
247 """@namespace IMP::test
248  @brief Methods and classes for testing the IMP kernel and modules.
249  @ingroup python
250 """
251 
252 import re, math
253 import sys
254 import os
255 import re
256 import tempfile
257 import random
258 import IMP
259 import time
260 import types
261 import shutil
262 import _compat_python
263 import _compat_python.unittest2
264 import datetime
265 
266 # Fall back to the sets.Set class on older Pythons that don't have
267 # the 'set' builtin type.
268 try:
269  set = set
270 except NameError:
271  import sets
272  set = sets.Set
273 
274 # Load a new enough unittest package (should have the 'skip' decorator)
275 # - On Python 2.7 or 3.2, the standard 'unittest' package will work.
276 # - On older Pythons, use the 'unittest2' package if available, otherwise use
277 # our bundled version of this package.
278 def __load_unittest_package():
279  errors = []
280  for modname, fromlist in (('unittest', []),
281  ('unittest2', []),
282  ):
283  try:
284  u = __import__(modname, {}, {}, fromlist)
285  if hasattr(u, 'skip'):
286  return u
287  else:
288  errors.append("'%s' does not have the 'skip' decorator" \
289  % modname)
290  except ImportError, e:
291  errors.append(str(e))
292  #u = __import__("_compat_python.unittest2
293  return _compat_python.unittest2
294  raise ImportError("IMP.test requires a newer version of Python's unittest "
295  "package than is available. Either upgrade to a new "
296  "enough Python (at least 2.7 or 3.2) or install the "
297  "unittest2 package. Encountered errors: %s" \
298  % "; ".join(errors))
299 unittest = __load_unittest_package()
300 
301 # Expose some unittest decorators for convenience
302 expectedFailure = unittest.expectedFailure
303 skip = unittest.skip
304 skipIf = unittest.skipIf
305 skipUnless = unittest.skipUnless
306 
307 class RunInTempDir(object):
308  """Simple RAII-style class to run in a temporary directory.
309  When the object is created, the temporary directory is created
310  and becomes the current working directory. When the object goes out
311  of scope, the working directory is reset and the temporary directory
312  deleted."""
313  def __init__(self):
314  self.origdir = os.getcwd()
315  self.tmpdir = tempfile.mkdtemp()
316  os.chdir(self.tmpdir)
317  def __del__(self):
318  os.chdir(self.origdir)
319  shutil.rmtree(self.tmpdir, ignore_errors=True)
320 
321 
322 def numerical_derivative(func, val, step):
323  """Calculate the derivative of the single-value function `func` at
324  point `val`. The derivative is calculated using simple finite
325  differences starting with the given `step`; Richardson extrapolation
326  is then used to extrapolate the derivative at step=0."""
327  maxsteps = 50
328  con = 1.4
329  safe = 2.0
330  err = 1.0e30
331  f1 = func(val + step)
332  f2 = func(val - step)
333  # create first element in triangular matrix d of derivatives
334  d = [[(f1 - f2) / (2.0 * step)]]
335  retval = None
336  for i in range(1, maxsteps):
337  d.append([0.] * (i + 1))
338  step /= con
339  f1 = func(val + step)
340  f2 = func(val - step)
341  d[i][0] = (f1 - f2) / (2.0 * step)
342  fac = con * con
343  for j in range(1, i + 1):
344  d[i][j] = (d[i][j-1] * fac - d[i-1][j-1]) / (fac - 1.)
345  fac *= con * con
346  errt = max(abs(d[i][j] - d[i][j-1]),
347  abs(d[i][j] - d[i-1][j-1]))
348  if errt <= err:
349  err = errt
350  retval = d[i][j]
351  if abs(d[i][i] - d[i-1][i-1]) >= safe * err:
352  break
353  if retval is None:
354  raise ValueError("Cannot calculate numerical derivative")
355  return retval
356 
357 
358 def xyz_numerical_derivatives(model, xyz, step):
359  """Calculate the x,y and z derivatives of `model`'s scoring function
360  on the `xyz` particle. The derivatives are approximated numerically
361  using the numerical_derivatives() function."""
362  class _XYZDerivativeFunc(object):
363  def __init__(self, xyz, basis_vector):
364  self._xyz = xyz
365  self._model = xyz.get_particle().get_model()
366  self._basis_vector = basis_vector
367  self._starting_coordinates = xyz.get_coordinates()
368 
369  def __call__(self, val):
370  self._xyz.set_coordinates(self._starting_coordinates + \
371  self._basis_vector * val)
372  return self._model.evaluate(False)
373 
374  return tuple([IMP.test.numerical_derivative(_XYZDerivativeFunc(xyz,
375  IMP.algebra.Vector3D(*x)), 0, 0.01) \
376  for x in ((1,0,0), (0,1,0), (0,0,1))])
377 
378 
379 class TestCase(unittest.TestCase):
380  """Super class for IMP test cases"""
381 
382  def setUp(self):
383  self.__check_level = IMP.base.get_check_level()
384  # Turn on expensive runtime checks while running the test suite:
385  IMP.base.set_check_level(IMP.base.USAGE_AND_INTERNAL)
386  # python ints are bigger than C++ ones, so we need to make sure it fits
387  # otherwise python throws fits
388  IMP.base.random_number_generator.seed(hash(time.time())%2**30)
389 
390  def tearDown(self):
391  # Restore original check level
392  IMP.base.set_check_level(self.__check_level)
393 
394  def get_input_file_name(self, filename):
395  """Get the full name of an input file in the top-level
396  test directory."""
397  # If we ran from run-all-tests.py, it set an env variable for us with
398  # the top-level test directory
399  if 'TEST_DIRECTORY' in os.environ:
400  top = os.environ['TEST_DIRECTORY']
401  return os.path.join(top, 'input', filename)
402  else:
403  # Otherwise, search up from the test's directory until we find
404  # the input directory
405  testdir = os.path.dirname(os.path.abspath(sys.argv[0]))
406  dirs = testdir.split(os.path.sep)
407  for i in range(len(dirs), 0, -1):
408  input = os.path.sep.join(dirs[:i] + ['input'])
409  if os.path.isdir(input):
410  return os.path.join(input, filename)
411  # If not found, default to the current working directory:
412  ret= os.path.join('input', filename)
413  if not open(ret, "r"):
414  raise IOError("Test input file "+ret+" does not exist")
415 
416  def open_input_file(self, filename, mode='rb'):
417  """Open and return an input file in the top-level test directory."""
418  return open(self.get_input_file_name(filename), mode)
419 
420  def get_tmp_file_name(self, filename):
421  """Get the full name of an output file in the build/tmp directory."""
422  dirpath=os.environ['IMP_TMP_DIR']
423  if not os.path.exists(dirpath):
424  os.mkdir(dirpath)
425  return os.path.join(dirpath, filename)
426 
427  def get_magnitude(self, vector):
428  return sum([x*x for x in vector], 0)**.5
429 
430  def assertXYZDerivativesInTolerance(self, model, xyz, tolerance=0,
431  percentage=0):
432  """Assert that x,y,z analytical derivatives match numerical within
433  a tolerance, or a percentage (of the analytical value), whichever
434  is larger."""
435  model.evaluate(True)
436  derivs = xyz.get_derivatives()
437  num_derivs = xyz_numerical_derivatives(model, xyz, 0.01)
438  pct = percentage / 100.0
439  self.assertAlmostEqual(self.get_magnitude(derivs-num_derivs),0,
440  delta=tolerance+percentage*self.get_magnitude(num_derivs),
441  msg="Don't match "+str(derivs) + str(num_derivs))
442  self.assertAlmostEqual(derivs[0], num_derivs[0],
443  delta=max(tolerance, abs(derivs[0]) * pct))
444  self.assertAlmostEqual(derivs[1], num_derivs[1],
445  delta=max(tolerance, abs(derivs[1]) * pct))
446  self.assertAlmostEqual(derivs[2], num_derivs[2],
447  delta=max(tolerance, abs(derivs[2]) * pct))
448 
449  def create_point_particle(self, model, x, y, z):
450  """Make a particle with optimizable x, y and z attributes, and
451  add it to the model."""
452  p = IMP.Particle(model)
453  p.add_attribute(IMP.FloatKey("x"), x, True)
454  p.add_attribute(IMP.FloatKey("y"), y, True)
455  p.add_attribute(IMP.FloatKey("z"), z, True)
456  return p
457 
458  def probabilistic_test(self, testcall, chance_of_failure):
459  """Help handle a test which is expected to fail some fraction of
460  the time. The test is run multiple times and an exception
461  is thrown only if it fails too many times."""
462  prob=chance_of_failure
463  tries=1
464  while prob > .001:
465  tries=tries+1
466  prob= prob*chance_of_failure
467  for i in range(0, tries):
468  try:
469  eval(testcall)
470  except:
471  pass
472  else:
473  return
474  eval(testcall)
475  raise AssertError("Too many failures")
476 
477  def failure_probability(self, testcall):
478  """Estimate how like a given block of code is to raise an
479  AssertionError."""
480  failures=0
481  tries=0.0
482  while failures < 10 and tries <1000:
483  try:
484  eval(testcall)
485  except:
486  failures=failures+1
487  tries=tries+1
488  return failures/tries
489 
490  def randomize_particles(self, particles, deviation):
491  """Randomize the xyz coordinates of a list of particles"""
492  # Note: cannot use XYZ here since that pulls in IMP.core
493  xkey = IMP.FloatKey("x")
494  ykey = IMP.FloatKey("y")
495  zkey = IMP.FloatKey("z")
496  for p in particles:
497  p.set_value(xkey, random.uniform(-deviation, deviation))
498  p.set_value(ykey, random.uniform(-deviation, deviation))
499  p.set_value(zkey, random.uniform(-deviation, deviation))
500 
501  def particle_distance(self, p1, p2):
502  """Return distance between two given particles"""
503  xkey = IMP.FloatKey("x")
504  ykey = IMP.FloatKey("y")
505  zkey = IMP.FloatKey("z")
506  dx = p1.get_value(xkey) - p2.get_value(xkey)
507  dy = p1.get_value(ykey) - p2.get_value(ykey)
508  dz = p1.get_value(zkey) - p2.get_value(zkey)
509  return math.sqrt(dx*dx + dy*dy + dz*dz)
510 
511  def check_unary_function_deriv(self, func, lb, ub, step):
512  """Check the unary function func's derivatives against numerical
513  approximations between lb and ub"""
514  for f in [lb + i * step for i in range(1, int((ub-lb)/step))]:
515  (v,d)= func.evaluate_with_derivative(f)
516  da = numerical_derivative(func.evaluate, f, step / 10.)
517  self.assertAlmostEqual(d, da, delta=max(abs(.1 *d), 0.01))
518 
519  def check_unary_function_min(self, func, lb, ub, step, expected_fmin):
520  """Make sure that the minimum of the unary function func over the
521  range between lb and ub is at expected_fmin"""
522  fmin, vmin = lb, func.evaluate(lb)
523  for f in [lb + i * step for i in range(1, int((ub-lb)/step))]:
524  v = func.evaluate(f)
525  if v < vmin:
526  fmin, vmin = f, v
527  self.assertAlmostEqual(fmin, expected_fmin, delta=step)
528 
529  def create_particles_in_box(self, model, num=10,
530  lb= [0,0,0],
531  ub= [10,10,10]):
532  """Create a bunch of particles in a box"""
533  import IMP.algebra
534  lbv=IMP.algebra.Vector3D(lb[0],lb[1],lb[2])
535  ubv=IMP.algebra.Vector3D(ub[0],ub[1],ub[2])
536  ps= []
537  for i in range(0,num):
539  p = self.create_point_particle(model, v[0], v[1], v[2])
540  ps.append(p)
541  return ps
542  def _get_type(self, module, name):
543  return eval('type('+module+"."+name+')')
544  def assertValueObjects(self, module, exceptions):
545  "Check that all the C++ classes in the module are values or objects."
546  all= dir(module)
547  bad=[]
548  for name in all:
549  if self._get_type(module.__name__, name)==types.TypeType and not name.startswith("_"):
550  if name.find("SwigPyIterator") != -1:
551  continue
552  # Exclude Python-only classes
553  if not eval('hasattr(%s.%s, "__swig_destroy__")' \
554  % (module.__name__, name)):
555  continue
556  if name in exceptions:
557  continue
558  if name not in eval(module.__name__+"._value_types")\
559  and name not in eval(module.__name__+"._object_types")\
560  and name not in eval(module.__name__+"._raii_types")\
561  and name not in eval(module.__name__+"._plural_types"):
562  bad.append(name)
563  message="All IMP classes should be labeled values or as objects to get memory management correct in python. The following are not:\n%s\nPlease add an IMP_SWIG_OBJECT or IMP_SWIG_VALUE call to the python wrapper, or if the class has a good reason to be neither, add the name to the value_object_exceptions list in the IMPModuleTest call." \
564  % (str(bad))
565  self.assertEquals(len(bad), 0,
566  message)
567  for e in exceptions:
568  self.assertTrue(e not in eval(module.__name__+"._value_types")\
569  + eval(module.__name__+"._object_types")\
570  + eval(module.__name__+"._raii_types")\
571  + eval(module.__name__+"._plural_types"),
572  "Value/Object exception "+e+" is not an exception")
573 
574  def _check_spelling(self, word, words):
575  """Check that the word is spelled correctly"""
576  if "words" not in dir(self):
577  wordlist= open(IMP.test.get_data_path("linux.words"), "r").read().split("\n")
578  # why is "all" missing on my mac?
579  custom_words=["info", "prechange", "int", "ints", "optimizeds", "graphviz",
580  "voxel", "voxels", "endian", 'rna', 'dna',
581  "xyzr", "pdbs", "fft", "ccc"]
582  self.words=set(wordlist+custom_words)
583  if self.words:
584  for i in "0123456789":
585  if i in word:
586  return True
587  if word in words:
588  return True
589  if word in self.words:
590  return True
591  else:
592  return False
593  else:
594  return True
595  def assertClassNames(self, module, exceptions, words):
596  """Check that all the classes in the module follow the imp naming conventions."""
597  all= dir(module)
598  misspelled = []
599  bad=[]
600  cc=re.compile("([A-Z][a-z]*)")
601  for name in all:
602  if self._get_type(module.__name__, name)==types.TypeType and not name.startswith("_"):
603  if name.find("SwigPyIterator") != -1:
604  continue
605  for t in re.findall(cc, name):
606  if not self._check_spelling(t.lower(), words):
607  misspelled.append(t.lower())
608  bad.append(name)
609 
610  self.assertEquals(len(bad), 0,
611  "All IMP classes should be properly spelled. The following are not: %s.\nMisspelled words: %s. Add words to the spelling_exceptions variable of the IMPModuleTest if needed." \
612  % (str(bad), ", ".join(set(misspelled))))
613 
614  for name in all:
615  if self._get_type(module.__name__, name)==types.TypeType and not name.startswith("_"):
616  if name.find("SwigPyIterator") != -1:
617  continue
618  if name.find('_') != -1:
619  bad.append(name)
620  if name.lower== name:
621  bad.append(name)
622  for t in re.findall(cc, name):
623  if not self._check_spelling(t.lower(), words):
624  print "misspelled", t, "in", name
625  bad.append(name)
626  message="All IMP classes should have CamelCase names. The following do not: %s." \
627  % ("\n".join(bad))
628  self.assertEquals(len(bad), 0,
629  message)
630 
631 
632  def _check_function_name(self, prefix, name, verbs, all, exceptions, words,
633  misspelled):
634  if prefix:
635  fullname=prefix+"."+name
636  else:
637  fullname=name
638  old_exceptions=['unprotected_evaluate', "unprotected_evaluate_if_good",
639  "unprotected_evaluate_if_below",
640  "after_evaluate", "before_evaluate", "has_attribute",
641  "decorate_particle","particle_is_instance"]
642  if name in old_exceptions:
643  return []
644  #print "name", fullname
645  if fullname in exceptions:
646  return []
647  if name.endswith("swigregister"):
648  return []
649  if name.lower() != name:
650  if name[0].lower() != name[0] and name.split('_')[0] in all:
651  # static methods
652  return []
653  else:
654  return [fullname]
655  starts=False
656  for v in verbs:
657  if name.startswith(v):
658  starts=True
659  break
660  if not starts:
661  return [fullname]
662  tokens= name.split("_")
663  for t in tokens:
664  if not self._check_spelling(t, words):
665  misspelled.append(t)
666  print "misspelled", t, "in", name
667  return [fullname]
668  return []
669  def _check_function_names(self, module, prefix, names, verbs, all, exceptions, words, misspelled):
670  bad=[]
671  #print "names", module, prefix
672  for name in names:
673  if name.startswith("_") or name =="weakref_proxy":
674  continue
675  if self._get_type(module, name)==types.BuiltinMethodType\
676  or self._get_type(module, name)==types.MethodType:
677  bad.extend(self._check_function_name(prefix, name, verbs, all, exceptions, words, misspelled))
678  if self._get_type(module, name)==types.TypeType and name.find("SwigPyIterator")==-1:
679  #print "sub", module+"."+name
680  members=eval("dir("+module+"."+name+")")
681  #print members
682  bad.extend(self._check_function_names(module+"."+name,
683  name,
684  members,
685  verbs, [], exceptions, words, misspelled))
686  return bad
687 
688 
689 
690  def assertFunctionNames(self, module, exceptions, words):
691  """Check that all the functions in the module follow the imp naming conventions."""
692  all= dir(module)
693  verbs=["add", "remove", "get", "set", "evaluate", "compute", "show", "create", "destroy",
694  "push", "pop", "write", "read", "do", "show", "load", "save", "reset",
695  "accept", "reject",
696  "clear", "handle", "update", "apply", "optimize", "reserve", "dump",
697  "propose", "setup", "teardown", "visit", "find", "run", "swap", "link",
698  "validate"]
699  misspelled = []
700  bad=self._check_function_names(module.__name__, None, all, verbs, all, exceptions, words, misspelled)
701  message="All IMP methods should have lower case names separated by underscores and beginning with a verb, preferably one of ['add', 'remove', 'get', 'set', 'create', 'destroy']. Each of the words should be a properly spelled english word. The following do not (given our limited list of verbs that we check for):\n%(bad)s\nIf there is a good reason for them not to (eg it does start with a verb, just one with a meaning that is not covered by the normal list), add them to the function_name_exceptions variable in the IMPModuleTest call. Otherwise, please fix. The current verb list is %(verbs)s" \
702  % {"bad":"\n".join(bad), "verbs":verbs}
703  if len(misspelled) > 0:
704  message += "\nMisspelled words: " + ", ".join(set(misspelled)) \
705  + ". Add words to the spelling_exceptions variable " \
706  + "of the IMPModuleTest if needed."
707  self.assertEquals(len(bad), 0,
708  message)
709 
710 
711  def assertShow(self, modulename, exceptions):
712  """Check that all the classes in modulename have a show method"""
713  all= dir(modulename)
714  not_found=[]
715  for f in all:
716  # Exclude Python-only classes; they are all showable
717  if not eval('hasattr(%s.%s, "__swig_destroy__")' \
718  % (modulename.__name__, f)):
719  continue
720  if self._get_type(modulename.__name__, f) == types.TypeType\
721  and not f.startswith("_") \
722  and not f.endswith("_swigregister")\
723  and f not in exceptions\
724  and not f.endswith("Temp") and not f.endswith("Iterator")\
725  and not f.endswith("Exception") and\
726  f not in eval(modulename.__name__+"._raii_types") and \
727  f not in eval(modulename.__name__+"._plural_types"):
728  if not hasattr(getattr(modulename, f), 'show'):
729  not_found.append(f)
730  message="All IMP classes should support show and __str__. The following do not:\n%s\n If there is a good reason for them not to, add them to the show_exceptions variable in the IMPModuleTest call. Otherwise, please fix." \
731  % "\n".join(not_found)
732  self.assertEquals(len(not_found), 0,
733  message)
734  for e in exceptions:
735  self.assertIn(e, all, "Show exception "+e+" is not a class in module")
736  self.assertTrue(not hasattr(getattr(modulename, e), 'show'),
737  "Exception "+e+" is not really a show exception")
738 
739  def run_example(self, filename):
740  """Run the named example script.
741  A dictionary of all the script's global variables is returned.
742  This can be queried in a test case to make sure the example
743  performed correctly."""
744  class _FatalError(Exception): pass
745 
746  # Add directory containing the example to sys.path, so it can import
747  # other Python modules in the same directory
748  path, name = os.path.split(filename)
749  oldsyspath = sys.path[:]
750  olssysargv= sys.argv[:]
751  sys.path.insert(0, path)
752  sys.argv=[filename]
753  vars = {}
754  try:
755  try:
756  exec open(filename) in vars
757  # Catch sys.exit() called from within the example; a non-zero exit
758  # value should cause the test case to fail
759  except SystemExit, e:
760  if e.code != 0 and e.code is not None:
761  raise _FatalError("Example exit with code %s" % str(e.code))
762  finally:
763  # Restore sys.path (note that Python 2.3 does not allow
764  # try/except/finally, so we need to use nested trys)
765  sys.path = oldsyspath
766  sys.argv= olssysargv
767 
768  return _ExecDictProxy(vars)
769 
770  def run_python_module(self, module, args):
771  """Run a Python module as if with "python -m <modname>",
772  with the given list of arguments as sys.argv.
773 
774  If module is an already-imported Python module, run its 'main'
775  function and return the result.
776 
777  If module is a string, run the module in a subprocess and return
778  a subprocess.Popen-like object containing the child stdin,
779  stdout and stderr.
780  """
781  if type(module) == type(os):
782  mod = module
783  else:
784  mod = __import__(module, {}, {}, [''])
785  modpath = mod.__file__
786  if modpath.endswith('.pyc'):
787  modpath = modpath[:-1]
788  if type(module) == type(os):
789  old_sys_argv = sys.argv
790  try:
791  sys.argv = [modpath] + args
792  return module.main()
793  finally:
794  sys.argv = old_sys_argv
795  else:
796  return _SubprocessWrapper(sys.executable, [modpath] + args)
797 
798  def check_runnable_python_module(self, module):
799  """Check a Python module designed to be runnable with 'python -m'
800  to make sure it supports standard command line options."""
801  # --help should return with exit 0, no errors
802  r = self.run_python_module(module, ['--help'])
803  out, err = r.communicate()
804  self.assertEqual(r.returncode, 0)
805  self.assertEqual(err, "")
806  self.assertNotEqual(out, "")
807 
808 
809 class _ExecDictProxy(object):
810  """exec returns a Python dictionary, which contains IMP objects, other
811  Python objects, as well as base Python modules (such as sys and
812  __builtins__). If we just delete this dictionary, it is entirely
813  possible that base Python modules are removed from the dictionary
814  *before* some IMP objects. This will prevent the IMP objects' Python
815  destructors from running properly, so C++ objects will not be
816  cleaned up. This class proxies the base dict class, and on deletion
817  attempts to remove keys from the dictionary in an order that allows
818  IMP destructors to fire."""
819  def __init__(self, d):
820  self._d = d
821  def __del__(self):
822  # Try to release example objects in a sensible order
823  module_type = type(IMP)
824  d = self._d
825  for k in d.keys():
826  if type(d[k]) != module_type:
827  del d[k]
828 
829  for meth in ['__contains__', '__getitem__', '__iter__', '__len__',
830  'get', 'has_key', 'items', 'keys', 'values']:
831  exec("def %s(self, *args, **keys): "
832  "return self._d.%s(*args, **keys)" % (meth, meth))
833 
834 
835 class _TestResult(unittest.TextTestResult):
836 
837  def __init__(self, stream=None, descriptions=None, verbosity=None):
838  super(_TestResult, self).__init__(stream, descriptions, verbosity)
839  self.all_tests = []
840  self._test_names = {}
841  self._duplicated_tests = {}
842 
843  def stopTestRun(self):
844  # Check for multiple tests which have the same name. Since tests are
845  # tracked by name, duplicates will make it difficult for developers
846  # to figure out which tests are failing. Report duplicates as an
847  # extra test failure.
848  class _DuplicateTest(object):
849  def shortDescription(self):
850  return 'Duplicate test names found'
851 
852  if len(self._duplicated_tests) > 0:
853  self.errors.append((_DuplicateTest(),
854  'Test case names must be unique, so that '
855  'failures can be easily tracked.\n'
856  'Please rename test(s) so that they are. '
857  'The following test case names\n'
858  'are duplicated:\n' \
859  + '\n'.join(self._duplicated_tests.keys())))
860  super(_TestResult, self).stopTestRun()
861 
862  def startTest(self, test):
863  super(_TestResult, self).startTest(test)
864  test.start_time=datetime.datetime.now()
865 
866  def _test_finished(self, test, state, detail=None):
867  delta = datetime.datetime.now() - test.start_time
868  try:
869  pv= delta.total_seconds()
870  except AttributeError:
871  pv = (float(delta.microseconds) \
872  + (delta.seconds + delta.days * 24 * 3600) * 10**6) / 10**6
873  if pv > 1:
874  self.stream.write("in %.3fs ... " % pv)
875  if detail is not None and not isinstance(detail, str):
876  detail = self._exc_info_to_string(detail, test)
877  test_name = self.getDescription(test)
878  if test_name in self._test_names:
879  self._duplicated_tests[test_name] = None
880  else:
881  self._test_names[test_name] = None
882  self.all_tests.append({'name': test_name,
883  'time': pv, 'state': state, 'detail': detail})
884 
885  def addSuccess(self, test):
886  self._test_finished(test, 'OK')
887  super(_TestResult, self).addSuccess(test)
888 
889  def addError(self, test, err):
890  self._test_finished(test, 'ERROR', err)
891  super(_TestResult, self).addError(test, err)
892 
893  def addFailure(self, test, err):
894  self._test_finished(test, 'FAIL', err)
895  super(_TestResult, self).addFailure(test, err)
896 
897  def addSkip(self, test, reason):
898  self._test_finished(test, 'SKIP', reason)
899  super(_TestResult, self).addSkip(test, reason)
900 
901  def addExpectedFailure(self, test, err):
902  self._test_finished(test, 'EXPFAIL', err)
903  super(_TestResult, self).addExpectedFailure(test, err)
904 
905  def addUnexpectedSuccess(self, test):
906  self._test_finished(test, 'UNEXPSUC', err)
907  super(_TestResult, self).addUnexpectedSuccess(test)
908 
909  def getDescription(self, test):
910  doc_first_line = test.shortDescription()
911  if self.descriptions and doc_first_line:
912  return doc_first_line
913  else:
914  return str(test)
915 
916 
917 class _TestRunner(unittest.TextTestRunner):
918  def _makeResult(self):
919  return _TestResult(self.stream, self.descriptions, self.verbosity)
920 
921 
922 def main(*args, **keys):
923  """Run a set of tests; essentially the same as unittest.main(). Obviates
924  the need to separately import the 'unittest' module, and ensures that
925  main() is from the same unittest module that the IMP.test testcases
926  are."""
927  return unittest.main(testRunner=_TestRunner, *args, **keys)
928 
929 try:
930  import subprocess
931  class _SubprocessWrapper(subprocess.Popen):
932  def __init__(self, app, args):
933  # For (non-Python) applications to work on Windows, the
934  # PATH must include the directory containing built DLLs
935  if sys.platform == 'win32' and app != sys.executable:
936  # Hack to find the location of build/lib/
937  libdir = os.environ['PYTHONPATH'].split(';')[0]
938  env = os.environ.copy()
939  env['PATH'] += ';' + libdir
940  else:
941  env = None
942  subprocess.Popen.__init__(self, [app]+list(args),
943  stdin=subprocess.PIPE,
944  stdout=subprocess.PIPE,
945  stderr=subprocess.PIPE, env=env)
946 except ImportError:
947  import threading
948  import popen2
949  # Provide a subprocess workalike for Python 2.3 systems (e.g. old Macs)
950  class _SubprocessWrapper(object):
951  def __init__(self, app, args):
952  self.popen = popen2.Popen3(app + " " + " ".join(args), True)
953  self.stdin = self.popen.tochild
954  self.stdout = self.popen.fromchild
955  self.stderr = self.popen.childerr
956 
957  def _readerthread(self, fh, buffer):
958  buffer.append(fh.read())
959 
960  def communicate(self, input=None):
961  stdout = []
962  stderr = []
963  stdout_thread = threading.Thread(target=self._readerthread,
964  args=(self.stdout, stdout))
965  stdout_thread.setDaemon(True)
966  stdout_thread.start()
967  stderr_thread = threading.Thread(target=self._readerthread,
968  args=(self.stderr, stderr))
969  stderr_thread.setDaemon(True)
970  stderr_thread.start()
971 
972  if input:
973  self.stdin.write(input)
974  self.stdin.close()
975  stdout_thread.join()
976  stderr_thread.join()
977  self.returncode = self.popen.wait()
978  return stdout[0], stderr[0]
979 
980 
982  """Super class for simple IMP application test cases"""
983  def _get_application_file_name(self, filename):
984  # If we ran from run-all-tests.py, it set an env variable for us with
985  # the top-level test directory
986  if sys.platform == 'win32':
987  filename += '.exe'
988  #if 'IMP_BUILD_ROOT' in os.environ:
989  # testdir = os.environ['IMP_BUILD_ROOT']
990  # return os.path.join(testdir, "build", "bin", filename)
991  return filename
992 
993  def run_application(self, app, args):
994  """Run an application with the given list of arguments.
995  @return a subprocess.Popen-like object containing the child stdin,
996  stdout and stderr.
997  """
998  filename = self._get_application_file_name(app)
999  if sys.platform == 'win32':
1000  # Cannot rely on PATH on wine builds, so use full pathname
1001  return _SubprocessWrapper(os.path.join(os.environ['IMP_BIN_DIR'],
1002  filename), args)
1003  else:
1004  return _SubprocessWrapper(filename, args)
1005 
1006  def run_python_application(self, app, args):
1007  """Run a Python application with the given list of arguments.
1008  The Python application should be self-runnable (i.e. it should
1009  be executable and with a #! on the first line).
1010  @return a subprocess.Popen-like object containing the child stdin,
1011  stdout and stderr.
1012  """
1013  # Handle platforms where /usr/bin/python doesn't work
1014  if sys.executable != '/usr/bin/python':
1015  return _SubprocessWrapper(sys.executable,
1016  [os.path.join(os.environ['IMP_BIN_DIR'], app)] + args)
1017  else:
1018  return _SubprocessWrapper(app, args)
1019 
1020  def import_python_application(self, app):
1021  """Import an installed Python application, rather than running it.
1022  This is useful to directly test components of the application.
1023  @return the Python module object."""
1024  import imp
1025  return imp.load_source(os.path.splitext(app)[0],
1026  os.path.join(os.environ['IMP_BIN_DIR'], app))
1027 
1028  def run_script(self, app, args):
1029  """Run an application with the given list of arguments.
1030  @return a subprocess.Popen-like object containing the child stdin,
1031  stdout and stderr.
1032  """
1033  return _SubprocessWrapper(sys.executable, [app]+args)
1034 
1035  def assertApplicationExitedCleanly(self, ret, error):
1036  """Assert that the application exited cleanly, i.e. that the
1037  return value is zero."""
1038  if ret < 0:
1039  raise OSError("Application exited with signal %d\n" % -ret\
1040  +error)
1041  else:
1042  self.assertEqual(ret, 0,
1043  "Application exited uncleanly, with exit code %d\n" % ret\
1044  + error)
1045 
1046  def read_shell_commands(self, doxfile):
1047  """Read and return a set of shell commands from a doxygen file.
1048  Each command is assumed to be in a \code{.sh}...\endcode block.
1049  The doxygen file is specified relative to the test file itself.
1050  This is used to make sure the commands shown in an application
1051  example actually work (the testcase can also check the resulting
1052  files for correctness)."""
1053  def fix_win32_command(cmd):
1054  # Make substitutions so a Unix shell command works on Windows
1055  if cmd.startswith('cp -r '):
1056  return 'xcopy /E ' + cmd[6:]
1057  elif cmd.startswith('cp '):
1058  return 'copy ' + cmd[3:]
1059  else:
1060  return cmd
1061  d = os.path.dirname(sys.argv[0])
1062  doc = os.path.join(d, doxfile)
1063  inline = False
1064  cmds = []
1065  example_path = os.path.abspath(IMP.get_example_path('..'))
1066  for line in open(doc).readlines():
1067  if '\code{.sh}' in line:
1068  inline = True
1069  elif '\endcode' in line:
1070  inline = False
1071  elif inline:
1072  cmds.append(line.rstrip('\r\n').replace('<imp_example_path>',
1073  example_path))
1074  if sys.platform == 'win32':
1075  cmds = [fix_win32_command(x) for x in cmds]
1076  return cmds
1077 
1078  def run_shell_command(self, cmd):
1079  "Print and run a shell command, as returned by read_shell_commands()"
1080  import subprocess
1081  print cmd
1082  p = subprocess.call(cmd, shell=True)
1083  if p != 0:
1084  raise OSError("%s failed with exit value %d" % (cmd, p))
1085 
1086 
1087 class RefCountChecker(object):
1088  """Check to make sure the number of C++ object references is as expected"""
1089 
1090  def __init__(self, testcase):
1091  # Make sure no director objects are hanging around; otherwise these
1092  # may be unexpectedly garbage collected later, decreasing the
1093  # live object count
1094  IMP.base._director_objects.cleanup()
1095  self.__testcase = testcase
1096  if IMP.base.get_check_level() >= IMP.base.USAGE_AND_INTERNAL:
1097  self.__basenum = IMP.base.RefCounted.get_number_of_live_objects()
1098  self.__names= IMP.base.get_live_object_names()
1099 
1100  def assert_number(self, expected):
1101  "Make sure that the number of references matches the expected value."
1102  t = self.__testcase
1103  IMP.base._director_objects.cleanup()
1104  if IMP.base.get_check_level() >= IMP.base.USAGE_AND_INTERNAL:
1105  newnames=[x for x in IMP.base.get_live_object_names() if x not in self.__names]
1106  newnum=IMP.base.RefCounted.get_number_of_live_objects()-self.__basenum
1107  t.assertEqual(newnum, expected,
1108  "Number of objects don't match: "\
1109  +str(newnum)\
1110  +" != "+ str(expected) +" found "+\
1111  str(newnames))
1112 
1113 
1114 
1115 class DirectorObjectChecker(object):
1116  """Check to make sure the number of director references is as expected"""
1117 
1118  def __init__(self, testcase):
1119  IMP.base._director_objects.cleanup()
1120  self.__testcase = testcase
1121  self.__basenum = IMP.base._director_objects.get_object_count()
1122 
1123  def assert_number(self, expected, force_cleanup=True):
1124  """Make sure that the number of references matches the expected value.
1125  If force_cleanup is set, clean up any unused references first before
1126  doing the assertion.
1127  """
1128  t = self.__testcase
1129  if force_cleanup:
1130  IMP.base._director_objects.cleanup()
1131  t.assertEqual(IMP.base._director_objects.get_object_count() \
1132  - self.__basenum, expected)
1133 
1134 # Make sure that the IMP binary directory (build/bin) is in the PATH, if
1135 # we're running under wine (the imppy.sh script normally ensures this, but
1136 # wine overrides the PATH). This is needed so that tests of imported Python
1137 # applications can successfully spawn C++ applications (e.g. idock.py tries
1138 # to run recompute_zscore.exe). build/lib also needs to be in the PATH, since
1139 # that's how Windows locates dependent DLLs such as libimp.dll.
1140 if sys.platform == 'win32' and 'PYTHONPATH' in os.environ \
1141  and 'IMP_BIN_DIR' in os.environ:
1142  libdir = os.environ['PYTHONPATH'].split(';')[0]
1143  bindir = os.environ['IMP_BIN_DIR']
1144  path = os.environ['PATH']
1145  if libdir not in path or bindir not in path:
1146  os.environ['PATH'] = bindir + ';' + libdir + ';' + path
1147 
1148 
1149 def get_module_version():
1150  """get_module_version() -> std::string const"""
1151  return _IMP_test.get_module_version()
1152 
1153 def get_example_path(*args):
1154  """get_example_path(std::string fname) -> std::string"""
1155  return _IMP_test.get_example_path(*args)
1156 
1157 def get_data_path(*args):
1158  """get_data_path(std::string fname) -> std::string"""
1159  return _IMP_test.get_data_path(*args)
1160 import _version_check
1161 _version_check.check_version(get_module_version())
1162 
1163 # This file is compatible with both classic and new-style classes.
1164 
1165