9 from sys
import version_info
10 if version_info >= (2,6,0):
11 def swig_import_helper():
12 from os.path
import dirname
16 fp, pathname, description = imp.find_module(
'_IMP_test', [dirname(__file__)])
22 _mod = imp.load_module(
'_IMP_test', fp, pathname, description)
26 _IMP_test = swig_import_helper()
27 del swig_import_helper
32 _swig_property = property
35 def _swig_setattr_nondynamic(self,class_type,name,value,static=1):
36 if (name ==
"thisown"):
return self.this.own(value)
38 if type(value).__name__ ==
'SwigPyObject':
39 self.__dict__[name] = value
41 method = class_type.__swig_setmethods__.get(name,
None)
42 if method:
return method(self,value)
44 self.__dict__[name] = value
46 raise AttributeError(
"You cannot add attributes to %s" % self)
48 def _swig_setattr(self,class_type,name,value):
49 return _swig_setattr_nondynamic(self,class_type,name,value,0)
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)
58 try: strthis =
"proxy of " + self.this.__repr__()
60 return "<%s.%s; %s >" % (self.__class__.__module__, self.__class__.__name__, strthis,)
65 except AttributeError:
72 weakref_proxy = weakref.proxy
74 weakref_proxy =
lambda x: x
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")
85 __swig_destroy__ = _IMP_test.delete_IMP_TEST_SwigPyIterator
86 __del__ =
lambda self :
None;
88 """value(IMP_TEST_SwigPyIterator self) -> PyObject *"""
89 return _IMP_test.IMP_TEST_SwigPyIterator_value(self)
93 incr(IMP_TEST_SwigPyIterator self, size_t n=1) -> IMP_TEST_SwigPyIterator
94 incr(IMP_TEST_SwigPyIterator self) -> IMP_TEST_SwigPyIterator
96 return _IMP_test.IMP_TEST_SwigPyIterator_incr(self, n)
100 decr(IMP_TEST_SwigPyIterator self, size_t n=1) -> IMP_TEST_SwigPyIterator
101 decr(IMP_TEST_SwigPyIterator self) -> IMP_TEST_SwigPyIterator
103 return _IMP_test.IMP_TEST_SwigPyIterator_decr(self, n)
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)
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)
114 """copy(IMP_TEST_SwigPyIterator self) -> IMP_TEST_SwigPyIterator"""
115 return _IMP_test.IMP_TEST_SwigPyIterator_copy(self)
118 """next(IMP_TEST_SwigPyIterator self) -> PyObject *"""
119 return _IMP_test.IMP_TEST_SwigPyIterator_next(self)
122 """__next__(IMP_TEST_SwigPyIterator self) -> PyObject *"""
123 return _IMP_test.IMP_TEST_SwigPyIterator___next__(self)
126 """previous(IMP_TEST_SwigPyIterator self) -> PyObject *"""
127 return _IMP_test.IMP_TEST_SwigPyIterator_previous(self)
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)
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)
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)
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)
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)
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)
153 def __sub__(self, *args):
155 __sub__(IMP_TEST_SwigPyIterator self, ptrdiff_t n) -> IMP_TEST_SwigPyIterator
156 __sub__(IMP_TEST_SwigPyIterator self, IMP_TEST_SwigPyIterator x) -> ptrdiff_t
158 return _IMP_test.IMP_TEST_SwigPyIterator___sub__(self, *args)
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)
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
188 class _DirectorObjects(object):
189 """@internal Simple class to keep references to director objects
190 to prevent premature deletion."""
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)
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]
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()
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
219 """set_check_level(IMP::base::CheckLevel tf)"""
220 return _IMP_test.set_check_level(*args)
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)
237 _ostream_swigregister = _IMP_test._ostream_swigregister
238 _ostream_swigregister(_ostream)
240 IMP_COMPILER_HAS_OVERRIDE = _IMP_test.IMP_COMPILER_HAS_OVERRIDE
241 IMP_COMPILER_HAS_FINAL = _IMP_test.IMP_COMPILER_HAS_FINAL
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.
262 import _compat_python
263 import _compat_python.unittest2
278 def __load_unittest_package():
280 for modname, fromlist
in ((
'unittest', []),
284 u = __import__(modname, {}, {}, fromlist)
285 if hasattr(u,
'skip'):
288 errors.append(
"'%s' does not have the 'skip' decorator" \
290 except ImportError, e:
291 errors.append(str(e))
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" \
299 unittest = __load_unittest_package()
302 expectedFailure = unittest.expectedFailure
304 skipIf = unittest.skipIf
305 skipUnless = unittest.skipUnless
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
314 self.origdir = os.getcwd()
315 self.tmpdir = tempfile.mkdtemp()
316 os.chdir(self.tmpdir)
318 os.chdir(self.origdir)
319 shutil.rmtree(self.tmpdir, ignore_errors=
True)
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."""
331 f1 = func(val + step)
332 f2 = func(val - step)
334 d = [[(f1 - f2) / (2.0 * step)]]
336 for i
in range(1, maxsteps):
337 d.append([0.] * (i + 1))
339 f1 = func(val + step)
340 f2 = func(val - step)
341 d[i][0] = (f1 - f2) / (2.0 * step)
343 for j
in range(1, i + 1):
344 d[i][j] = (d[i][j-1] * fac - d[i-1][j-1]) / (fac - 1.)
346 errt = max(abs(d[i][j] - d[i][j-1]),
347 abs(d[i][j] - d[i-1][j-1]))
351 if abs(d[i][i] - d[i-1][i-1]) >= safe * err:
354 raise ValueError(
"Cannot calculate numerical derivative")
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):
365 self._model = xyz.get_particle().get_model()
366 self._basis_vector = basis_vector
367 self._starting_coordinates = xyz.get_coordinates()
369 def __call__(self, val):
370 self._xyz.set_coordinates(self._starting_coordinates + \
371 self._basis_vector * val)
372 return self._model.evaluate(
False)
376 for x
in ((1,0,0), (0,1,0), (0,0,1))])
380 """Super class for IMP test cases"""
388 IMP.base.random_number_generator.seed(hash(time.time())%2**30)
394 def get_input_file_name(self, filename):
395 """Get the full name of an input file in the top-level
399 if 'TEST_DIRECTORY' in os.environ:
400 top = os.environ[
'TEST_DIRECTORY']
401 return os.path.join(top,
'input', filename)
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)
412 ret= os.path.join(
'input', filename)
413 if not open(ret,
"r"):
414 raise IOError(
"Test input file "+ret+
" does not exist")
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)
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):
425 return os.path.join(dirpath, filename)
427 def get_magnitude(self, vector):
428 return sum([x*x
for x
in vector], 0)**.5
430 def assertXYZDerivativesInTolerance(self, model, xyz, tolerance=0,
432 """Assert that x,y,z analytical derivatives match numerical within
433 a tolerance, or a percentage (of the analytical value), whichever
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))
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."""
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
466 prob= prob*chance_of_failure
467 for i
in range(0, tries):
475 raise AssertError(
"Too many failures")
477 def failure_probability(self, testcall):
478 """Estimate how like a given block of code is to raise an
482 while failures < 10
and tries <1000:
488 return failures/tries
491 """Randomize the xyz coordinates of a list of 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))
501 def particle_distance(self, p1, p2):
502 """Return distance between two given particles"""
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)
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))
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))]:
527 self.assertAlmostEqual(fmin, expected_fmin, delta=step)
529 def create_particles_in_box(self, model, num=10,
532 """Create a bunch of particles in a box"""
537 for i
in range(0,num):
539 p = self.create_point_particle(model, v[0], v[1], v[2])
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."
549 if self._get_type(module.__name__, name)==types.TypeType
and not name.startswith(
"_"):
550 if name.find(
"SwigPyIterator") != -1:
553 if not eval(
'hasattr(%s.%s, "__swig_destroy__")' \
554 % (module.__name__, name)):
556 if name
in exceptions:
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"):
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." \
565 self.assertEquals(len(bad), 0,
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")
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")
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)
584 for i
in "0123456789":
589 if word
in self.words:
595 def assertClassNames(self, module, exceptions, words):
596 """Check that all the classes in the module follow the imp naming conventions."""
600 cc=re.compile(
"([A-Z][a-z]*)")
602 if self._get_type(module.__name__, name)==types.TypeType
and not name.startswith(
"_"):
603 if name.find(
"SwigPyIterator") != -1:
605 for t
in re.findall(cc, name):
606 if not self._check_spelling(t.lower(), words):
607 misspelled.append(t.lower())
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))))
615 if self._get_type(module.__name__, name)==types.TypeType
and not name.startswith(
"_"):
616 if name.find(
"SwigPyIterator") != -1:
618 if name.find(
'_') != -1:
620 if name.lower== name:
622 for t
in re.findall(cc, name):
623 if not self._check_spelling(t.lower(), words):
624 print "misspelled", t,
"in", name
626 message=
"All IMP classes should have CamelCase names. The following do not: %s." \
628 self.assertEquals(len(bad), 0,
632 def _check_function_name(self, prefix, name, verbs, all, exceptions, words,
635 fullname=prefix+
"."+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:
645 if fullname
in exceptions:
647 if name.endswith(
"swigregister"):
649 if name.lower() != name:
650 if name[0].lower() != name[0]
and name.split(
'_')[0]
in all:
657 if name.startswith(v):
662 tokens= name.split(
"_")
664 if not self._check_spelling(t, words):
666 print "misspelled", t,
"in", name
669 def _check_function_names(self, module, prefix, names, verbs, all, exceptions, words, misspelled):
673 if name.startswith(
"_")
or name ==
"weakref_proxy":
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:
680 members=eval(
"dir("+module+
"."+name+
")")
682 bad.extend(self._check_function_names(module+
"."+name,
685 verbs, [], exceptions, words, misspelled))
690 def assertFunctionNames(self, module, exceptions, words):
691 """Check that all the functions in the module follow the imp naming conventions."""
693 verbs=[
"add",
"remove",
"get",
"set",
"evaluate",
"compute",
"show",
"create",
"destroy",
694 "push",
"pop",
"write",
"read",
"do",
"show",
"load",
"save",
"reset",
696 "clear",
"handle",
"update",
"apply",
"optimize",
"reserve",
"dump",
697 "propose",
"setup",
"teardown",
"visit",
"find",
"run",
"swap",
"link",
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,
711 def assertShow(self, modulename, exceptions):
712 """Check that all the classes in modulename have a show method"""
717 if not eval(
'hasattr(%s.%s, "__swig_destroy__")' \
718 % (modulename.__name__, f)):
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'):
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,
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")
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
748 path, name = os.path.split(filename)
749 oldsyspath = sys.path[:]
750 olssysargv= sys.argv[:]
751 sys.path.insert(0, path)
756 exec open(filename)
in vars
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))
765 sys.path = oldsyspath
768 return _ExecDictProxy(vars)
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.
774 If module is an already-imported Python module, run its 'main'
775 function and return the result.
777 If module is a string, run the module in a subprocess and return
778 a subprocess.Popen-like object containing the child stdin,
781 if type(module) == type(os):
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
791 sys.argv = [modpath] + args
794 sys.argv = old_sys_argv
796 return _SubprocessWrapper(sys.executable, [modpath] + args)
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."""
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,
"")
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):
823 module_type = type(IMP)
826 if type(d[k]) != module_type:
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))
835 class _TestResult(unittest.TextTestResult):
837 def __init__(self, stream=None, descriptions=None, verbosity=None):
838 super(_TestResult, self).__init__(stream, descriptions, verbosity)
840 self._test_names = {}
841 self._duplicated_tests = {}
843 def stopTestRun(self):
848 class _DuplicateTest(object):
849 def shortDescription(self):
850 return 'Duplicate test names found'
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()
862 def startTest(self, test):
863 super(_TestResult, self).startTest(test)
864 test.start_time=datetime.datetime.now()
866 def _test_finished(self, test, state, detail=None):
867 delta = datetime.datetime.now() - test.start_time
869 pv= delta.total_seconds()
870 except AttributeError:
871 pv = (float(delta.microseconds) \
872 + (delta.seconds + delta.days * 24 * 3600) * 10**6) / 10**6
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
881 self._test_names[test_name] =
None
882 self.all_tests.append({
'name': test_name,
883 'time': pv,
'state': state,
'detail': detail})
885 def addSuccess(self, test):
886 self._test_finished(test,
'OK')
887 super(_TestResult, self).addSuccess(test)
889 def addError(self, test, err):
890 self._test_finished(test,
'ERROR', err)
891 super(_TestResult, self).addError(test, err)
893 def addFailure(self, test, err):
894 self._test_finished(test,
'FAIL', err)
895 super(_TestResult, self).addFailure(test, err)
897 def addSkip(self, test, reason):
898 self._test_finished(test,
'SKIP', reason)
899 super(_TestResult, self).addSkip(test, reason)
901 def addExpectedFailure(self, test, err):
902 self._test_finished(test,
'EXPFAIL', err)
903 super(_TestResult, self).addExpectedFailure(test, err)
905 def addUnexpectedSuccess(self, test):
906 self._test_finished(test,
'UNEXPSUC', err)
907 super(_TestResult, self).addUnexpectedSuccess(test)
909 def getDescription(self, test):
910 doc_first_line = test.shortDescription()
911 if self.descriptions
and doc_first_line:
912 return doc_first_line
917 class _TestRunner(unittest.TextTestRunner):
918 def _makeResult(self):
919 return _TestResult(self.stream, self.descriptions, self.verbosity)
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
927 return unittest.main(testRunner=_TestRunner, *args, **keys)
931 class _SubprocessWrapper(subprocess.Popen):
932 def __init__(self, app, args):
935 if sys.platform ==
'win32' and app != sys.executable:
937 libdir = os.environ[
'PYTHONPATH'].split(
';')[0]
938 env = os.environ.copy()
939 env[
'PATH'] +=
';' + libdir
942 subprocess.Popen.__init__(self, [app]+list(args),
943 stdin=subprocess.PIPE,
944 stdout=subprocess.PIPE,
945 stderr=subprocess.PIPE, env=env)
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
957 def _readerthread(self, fh, buffer):
958 buffer.append(fh.read())
960 def communicate(self, input=None):
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()
973 self.stdin.write(input)
977 self.returncode = self.popen.wait()
978 return stdout[0], stderr[0]
982 """Super class for simple IMP application test cases"""
983 def _get_application_file_name(self, filename):
986 if sys.platform ==
'win32':
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,
998 filename = self._get_application_file_name(app)
999 if sys.platform ==
'win32':
1001 return _SubprocessWrapper(os.path.join(os.environ[
'IMP_BIN_DIR'],
1004 return _SubprocessWrapper(filename, args)
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,
1014 if sys.executable !=
'/usr/bin/python':
1015 return _SubprocessWrapper(sys.executable,
1016 [os.path.join(os.environ[
'IMP_BIN_DIR'], app)] + args)
1018 return _SubprocessWrapper(app, args)
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."""
1025 return imp.load_source(os.path.splitext(app)[0],
1026 os.path.join(os.environ[
'IMP_BIN_DIR'], app))
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,
1033 return _SubprocessWrapper(sys.executable, [app]+args)
1035 def assertApplicationExitedCleanly(self, ret, error):
1036 """Assert that the application exited cleanly, i.e. that the
1037 return value is zero."""
1039 raise OSError(
"Application exited with signal %d\n" % -ret\
1042 self.assertEqual(ret, 0,
1043 "Application exited uncleanly, with exit code %d\n" % ret\
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):
1055 if cmd.startswith(
'cp -r '):
1056 return 'xcopy /E ' + cmd[6:]
1057 elif cmd.startswith(
'cp '):
1058 return 'copy ' + cmd[3:]
1061 d = os.path.dirname(sys.argv[0])
1062 doc = os.path.join(d, doxfile)
1065 example_path = os.path.abspath(IMP.get_example_path(
'..'))
1066 for line
in open(doc).readlines():
1067 if '\code{.sh}' in line:
1069 elif '\endcode' in line:
1072 cmds.append(line.rstrip(
'\r\n').replace(
'<imp_example_path>',
1074 if sys.platform ==
'win32':
1075 cmds = [fix_win32_command(x)
for x
in cmds]
1078 def run_shell_command(self, cmd):
1079 "Print and run a shell command, as returned by read_shell_commands()"
1082 p = subprocess.call(cmd, shell=
True)
1084 raise OSError(
"%s failed with exit value %d" % (cmd, p))
1088 """Check to make sure the number of C++ object references is as expected"""
1090 def __init__(self, testcase):
1094 IMP.base._director_objects.cleanup()
1095 self.__testcase = testcase
1097 self.__basenum = IMP.base.RefCounted.get_number_of_live_objects()
1101 "Make sure that the number of references matches the expected value."
1103 IMP.base._director_objects.cleanup()
1106 newnum=IMP.base.RefCounted.get_number_of_live_objects()-self.__basenum
1107 t.assertEqual(newnum, expected,
1108 "Number of objects don't match: "\
1110 +
" != "+ str(expected) +
" found "+\
1116 """Check to make sure the number of director references is as expected"""
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()
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.
1130 IMP.base._director_objects.cleanup()
1131 t.assertEqual(IMP.base._director_objects.get_object_count() \
1132 - self.__basenum, expected)
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
1149 def get_module_version():
1150 """get_module_version() -> std::string const"""
1151 return _IMP_test.get_module_version()
1153 def get_example_path(*args):
1154 """get_example_path(std::string fname) -> std::string"""
1155 return _IMP_test.get_example_path(*args)
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())