1 """@namespace IMP::test
2 @brief Methods and classes for testing the IMP kernel and modules.
19 from unittest.util
import safe_repr
26 expectedFailure = unittest.expectedFailure
28 skipIf = unittest.skipIf
29 skipUnless = unittest.skipUnless
32 class _TempDir(object):
33 def __init__(self, dir=None):
34 self.tmpdir = tempfile.mkdtemp(dir=dir)
37 shutil.rmtree(self.tmpdir, ignore_errors=
True)
40 @contextlib.contextmanager
42 """Simple context manager to run in a temporary directory.
43 While the context manager is active (within the 'with' block)
44 the current working directory is set to a temporary directory.
45 When the context manager exists, the working directory is reset
46 and the temporary directory deleted."""
48 tmpdir = tempfile.mkdtemp()
52 shutil.rmtree(tmpdir, ignore_errors=
True)
55 @contextlib.contextmanager
57 """Simple context manager to make a temporary directory.
58 The temporary directory has the same lifetime as the context manager
59 (i.e. it is created at the start of the 'with' block, and deleted
60 at the end of the block).
61 @param dir If given, the temporary directory is made as a subdirectory
62 of that directory, rather than in the default temporary
63 directory location (e.g. /tmp)
64 @return the full path to the temporary directory.
66 tmpdir = tempfile.mkdtemp(dir=dir)
68 shutil.rmtree(tmpdir, ignore_errors=
True)
72 """Calculate the derivative of the single-value function `func` at
73 point `val`. The derivative is calculated using simple finite
74 differences starting with the given `step`; Richardson extrapolation
75 is then used to extrapolate the derivative at step=0."""
83 d = [[(f1 - f2) / (2.0 * step)]]
85 for i
in range(1, maxsteps):
86 d.append([0.] * (i + 1))
90 d[i][0] = (f1 - f2) / (2.0 * step)
92 for j
in range(1, i + 1):
93 d[i][j] = (d[i][j-1] * fac - d[i-1][j-1]) / (fac - 1.)
95 errt = max(abs(d[i][j] - d[i][j-1]),
96 abs(d[i][j] - d[i-1][j-1]))
100 if abs(d[i][i] - d[i-1][i-1]) >= safe * err:
103 raise ValueError(
"Cannot calculate numerical derivative")
108 """Calculate the x,y and z derivatives of the scoring function `sf`
109 on the `xyz` particle. The derivatives are approximated numerically
110 using the numerical_derivatives() function."""
111 class _XYZDerivativeFunc(object):
112 def __init__(self, sf, xyz, basis_vector):
115 self._basis_vector = basis_vector
116 self._starting_coordinates = xyz.get_coordinates()
118 def __call__(self, val):
119 self._xyz.set_coordinates(self._starting_coordinates +
120 self._basis_vector * val)
121 return self._sf.evaluate(
False)
126 for x
in ((1, 0, 0), (0, 1, 0), (0, 0, 1))])
130 """Super class for IMP test cases.
131 This provides a number of useful IMP-specific methods on top of
132 the standard Python `unittest.TestCase` class.
133 Test scripts should generally contain a subclass of this class,
134 conventionally called `Tests` (this makes it easier to run an
135 individual test from the command line) and use IMP::test::main()
136 as their main function."""
140 if not hasattr(unittest.TestCase,
'assertRegex'):
141 assertRegex = unittest.TestCase.assertRegexpMatches
142 assertNotRegex = unittest.TestCase.assertNotRegexpMatches
144 def __init__(self, *args, **keys):
145 unittest.TestCase.__init__(self, *args, **keys)
146 self._progname = os.path.abspath(sys.argv[0])
154 IMP.random_number_generator.seed(hash(time.time()) % 2**30)
160 if hasattr(self,
'_tmpdir'):
164 """Get the full name of an input file in the top-level
166 testdir = os.path.dirname(self._progname)
167 if self.__module__ !=
'__main__':
168 testdir = os.path.dirname(sys.modules[self.__module__].__file__)
169 dirs = testdir.split(os.path.sep)
170 for i
in range(len(dirs), 0, -1):
171 input = os.path.sep.join(dirs[:i] + [
'input'])
172 if os.path.isdir(input):
173 ret = os.path.join(input, filename)
174 if not os.path.exists(ret):
175 raise IOError(
"Test input file "+ret+
" does not exist")
177 raise IOError(
"No test input directory found")
180 """Open and return an input file in the top-level test directory."""
184 """Get the full name of an output file in the tmp directory.
185 The directory containing this file will be automatically
186 cleaned up when the test completes."""
187 if not hasattr(self,
'_tmpdir'):
188 self._tmpdir = _TempDir(os.environ.get(
'IMP_TMP_DIR'))
189 tmpdir = self._tmpdir.tmpdir
190 return os.path.join(tmpdir, filename)
193 """Get the magnitude of a list of floats"""
194 return sum([x*x
for x
in vector], 0)**.5
197 """Assert that the given callable object raises UsageException.
198 This differs from unittest's assertRaises in that the test
199 is skipped in fast mode (where usage checks are turned off)."""
204 """Assert that the given callable object raises InternalException.
205 This differs from unittest's assertRaises in that the test
206 is skipped in fast mode (where internal checks are turned off)."""
211 """Assert that the given callable object is not implemented."""
216 """Assert that x,y,z analytical derivatives match numerical within
217 a tolerance, or a percentage (of the analytical value), whichever
218 is larger. `sf` should be a ScoringFunction or Restraint,
219 although for backwards compatibility a Model is also accepted."""
221 derivs = xyz.get_derivatives()
223 pct = percentage / 100.0
224 self.assertAlmostEqual(
227 msg=
"Don't match "+str(derivs) + str(num_derivs))
228 self.assertAlmostEqual(derivs[0], num_derivs[0],
229 delta=max(tolerance, abs(derivs[0]) * pct))
230 self.assertAlmostEqual(derivs[1], num_derivs[1],
231 delta=max(tolerance, abs(derivs[1]) * pct))
232 self.assertAlmostEqual(derivs[2], num_derivs[2],
233 delta=max(tolerance, abs(derivs[2]) * pct))
236 """Fail if the given numpy array doesn't match expected"""
237 if IMP.IMP_KERNEL_HAS_NUMPY:
239 self.assertIsInstance(numpy_array, numpy.ndarray)
240 numpy.testing.assert_array_equal(numpy_array, exp_array)
242 self.assertEqual(numpy_array, exp_array)
246 """Fail if the difference between any two items in the two sequences
247 are exceed the specified number of places or delta. See
250 if delta
is not None and places
is not None:
251 raise TypeError(
"specify delta or places not both")
254 ftypename = ftype.__name__
256 stypename = stype.__name__
258 raise self.failureException(
259 'Sequences are of different types: %s != %s' % (
260 ftypename, stypename))
264 except (NotImplementedError, TypeError):
265 raise self.failureException(
266 'First %s has no length' % (ftypename))
269 except (NotImplementedError, TypeError):
270 raise self.failureException(
271 'Second %s has no length' % (stypename))
274 raise self.failureException(
275 'Sequences have non equal lengths: %d != %d' % (flen, slen))
278 for i
in range(min(flen, slen)):
279 differing =
'%ss differ: %s != %s\n' % (
280 ftypename.capitalize(), safe_repr(first),
285 except (TypeError, IndexError, NotImplementedError):
286 differing += (
'\nUnable to index element %d of first %s\n' %
292 except (TypeError, IndexError, NotImplementedError):
293 differing += (
'\nUnable to index element %d of second %s\n' %
298 self.assertAlmostEqual(
299 f, s, places=places, msg=msg, delta=delta)
300 except (TypeError, ValueError, NotImplementedError,
303 "\nFirst differing element "
304 "%d:\n%s\n%s\n") % (i, safe_repr(f), safe_repr(s))
309 standardMsg = differing
310 diffMsg =
'\n' +
'\n'.join(
311 difflib.ndiff(pprint.pformat(first).splitlines(),
312 pprint.pformat(second).splitlines()))
313 standardMsg = self._truncateMessage(standardMsg, diffMsg)
314 msg = self._formatMessage(msg, standardMsg)
315 raise self.failureException(msg)
318 """Make a particle with optimizable x, y and z attributes, and
319 add it to the model."""
327 """Help handle a test which is expected to fail some fraction of
328 the time. The test is run multiple times and an exception
329 is thrown only if it fails too many times.
330 @note Use of this function should be avoided. If there is a corner
331 case that results in a test 'occasionally' failing, write a
332 new test specifically for that corner case and assert that
333 it fails consistently (and remove the corner case from the
336 prob = chance_of_failure
340 prob = prob*chance_of_failure
341 for i
in range(0, tries):
349 raise AssertionError(
"Too many failures")
352 """Estimate how likely a given block of code is to raise an
356 while failures < 10
and tries < 1000:
362 return failures/tries
365 """Randomize the xyz coordinates of a list of particles"""
371 p.set_value(xkey, random.uniform(-deviation, deviation))
372 p.set_value(ykey, random.uniform(-deviation, deviation))
373 p.set_value(zkey, random.uniform(-deviation, deviation))
376 """Return distance between two given particles"""
380 dx = p1.get_value(xkey) - p2.get_value(xkey)
381 dy = p1.get_value(ykey) - p2.get_value(ykey)
382 dz = p1.get_value(zkey) - p2.get_value(zkey)
383 return math.sqrt(dx*dx + dy*dy + dz*dz)
386 """Check the unary function func's derivatives against numerical
387 approximations between lb and ub"""
388 for f
in [lb + i * step
for i
in range(1, int((ub-lb)/step))]:
389 (v, d) = func.evaluate_with_derivative(f)
391 self.assertAlmostEqual(d, da, delta=max(abs(.1 * d), 0.01))
394 """Make sure that the minimum of the unary function func over the
395 range between lb and ub is at expected_fmin"""
396 fmin, vmin = lb, func.evaluate(lb)
397 for f
in [lb + i * step
for i
in range(1, int((ub-lb)/step))]:
401 self.assertAlmostEqual(fmin, expected_fmin, delta=step)
404 """Check methods that every IMP::Object class should have"""
405 obj.set_was_used(
True)
408 self.assertIsNotNone(cls.get_from(obj))
409 self.assertRaises(ValueError, cls.get_from,
IMP.Model())
411 self.assertIsInstance(str(obj), str)
412 self.assertIsInstance(repr(obj), str)
414 verinf = obj.get_version_info()
423 """Create a bunch of particles in a box"""
428 for i
in range(0, num):
435 def _get_type(self, module, name):
436 return eval(
'type('+module+
"."+name+
')')
439 "Check that all the C++ classes in the module are values or objects."
441 ok = set(exceptions_list + module._value_types + module._object_types
442 + module._raii_types + module._plural_types)
446 if self._get_type(module.__name__, name) == type \
447 and not name.startswith(
"_"):
448 if name.find(
"SwigPyIterator") != -1:
451 if not eval(
'hasattr(%s.%s, "__swig_destroy__")'
452 % (module.__name__, name)):
459 "All IMP classes should be labeled as values or objects to get "
460 "memory management correct in Python. The following are not:\n%s\n"
461 "Please add an IMP_SWIG_OBJECT or IMP_SWIG_VALUE call to the "
462 "Python wrapper, or if the class has a good reason to be "
463 "neither, add the name to the value_object_exceptions list in "
464 "the IMPModuleTest call." % str(bad))
465 for e
in exceptions_list:
467 e
not in module._value_types + module._object_types
468 + module._raii_types + module._plural_types,
469 "Value/Object exception "+e+
" is not an exception")
471 def _check_spelling(self, word, words):
472 """Check that the word is spelled correctly"""
473 if "words" not in dir(self):
475 wordlist = fh.read().split("\n")
477 custom_words = [
"info",
"prechange",
"int",
"ints",
"optimizeds",
478 "graphviz",
"voxel",
"voxels",
"endian",
'rna',
479 'dna',
"xyzr",
"pdbs",
"fft",
"ccc",
"gaussian"]
482 exclude_words = set([
"adapter",
"grey"])
483 self.words = set(wordlist+custom_words) - exclude_words
485 for i
in "0123456789":
490 if word
in self.words:
498 """Check that all the classes in the module follow the IMP
499 naming conventions."""
503 cc = re.compile(
"([A-Z][a-z]*)")
505 if self._get_type(module.__name__, name) == type \
506 and not name.startswith(
"_"):
507 if name.find(
"SwigPyIterator") != -1:
509 for t
in re.findall(cc, name):
510 if not self._check_spelling(t.lower(), words):
511 misspelled.append(t.lower())
516 "All IMP classes should be properly spelled. The following "
517 "are not: %s.\nMisspelled words: %s. Add words to the "
518 "spelling_exceptions variable of the IMPModuleTest if needed."
519 % (str(bad),
", ".join(set(misspelled))))
522 if self._get_type(module.__name__, name) == type \
523 and not name.startswith(
"_"):
524 if name.find(
"SwigPyIterator") != -1:
526 if name.find(
'_') != -1:
528 if name.lower == name:
530 for t
in re.findall(cc, name):
531 if not self._check_spelling(t.lower(), words):
532 print(
"misspelled %s in %s" % (t, name))
536 "All IMP classes should have CamelCase names. The following "
537 "do not: %s." %
"\n".join(bad))
539 def _check_function_name(self, prefix, name, verbs, all, exceptions, words,
542 fullname = prefix+
"."+name
546 'unprotected_evaluate',
"unprotected_evaluate_if_good",
547 "unprotected_evaluate_if_below",
548 'unprotected_evaluate_moved',
"unprotected_evaluate_moved_if_good",
549 "unprotected_evaluate_moved_if_below",
550 "after_evaluate",
"before_evaluate",
"has_attribute",
551 "decorate_particle",
"particle_is_instance"]
552 if name
in old_exceptions:
554 if fullname
in exceptions:
556 if name.endswith(
"swigregister"):
558 if name.lower() != name:
559 if name[0].lower() != name[0]
and name.split(
'_')[0]
in all:
564 tokens = name.split(
"_")
565 if tokens[0]
not in verbs:
568 if not self._check_spelling(t, words):
570 print(
"misspelled %s in %s" % (t, name))
574 def _static_method(self, module, prefix, name):
575 """For static methods of the form Foo.bar SWIG creates free functions
576 named Foo_bar. Exclude these from spelling checks since the method
577 Foo.bar has already been checked."""
578 if prefix
is None and '_' in name:
579 modobj = eval(module)
580 cls, meth = name.split(
'_', 1)
581 if hasattr(modobj, cls):
582 clsobj = eval(module +
'.' + cls)
583 if hasattr(clsobj, meth):
586 def _check_function_names(self, module, prefix, names, verbs, all,
587 exceptions, words, misspelled):
590 typ = self._get_type(module, name)
591 if name.startswith(
"_")
or name ==
"weakref_proxy":
593 if typ
in (types.BuiltinMethodType, types.MethodType) \
594 or (typ == types.FunctionType
and
595 not self._static_method(module, prefix, name)):
596 bad.extend(self._check_function_name(prefix, name, verbs, all,
599 if typ == type
and "SwigPyIterator" not in name:
600 members = eval(
"dir("+module+
"."+name+
")")
601 bad.extend(self._check_function_names(module+
"."+name,
602 name, members, verbs, [],
608 """Check that all the functions in the module follow the IMP
609 naming conventions."""
611 verbs = set([
"add",
"remove",
"get",
"set",
"evaluate",
"compute",
612 "show",
"create",
"destroy",
"push",
"pop",
"write",
613 "read",
"do",
"show",
"load",
"save",
"reset",
"accept",
614 "reject",
"clear",
"handle",
"update",
"apply",
615 "optimize",
"reserve",
"dump",
"propose",
"setup",
616 "teardown",
"visit",
"find",
"run",
"swap",
"link",
619 bad = self._check_function_names(module.__name__,
None, all, verbs,
620 all, exceptions, words, misspelled)
621 message = (
"All IMP methods and functions should have lower case "
622 "names separated by underscores and beginning with a "
623 "verb, preferably one of ['add', 'remove', 'get', 'set', "
624 "'create', 'destroy']. Each of the words should be a "
625 "properly spelled English word. The following do not "
626 "(given our limited list of verbs that we check for):\n"
627 "%(bad)s\nIf there is a good reason for them not to "
628 "(eg it does start with a verb, just one with a meaning "
629 "that is not covered by the normal list), add them to the "
630 "function_name_exceptions variable in the "
631 "standards_exceptions file. Otherwise, please fix. "
632 "The current verb list is %(verbs)s"
633 % {
"bad":
"\n".join(bad),
"verbs": verbs})
634 if len(misspelled) > 0:
635 message +=
"\nMisspelled words: " +
", ".join(set(misspelled)) \
636 +
". Add words to the spelling_exceptions variable " \
637 +
"of the standards_exceptions file if needed."
638 self.assertEqual(len(bad), 0, message)
641 """Check that all the classes in modulename have a show method"""
642 all = dir(modulename)
649 if not eval(
'hasattr(%s.%s, "__swig_destroy__")'
650 % (modulename.__name__, f)):
652 if self._get_type(modulename.__name__, f) == type \
653 and not f.startswith(
"_") \
654 and not f.endswith(
"_swigregister")\
655 and f
not in exceptions\
656 and not f.endswith(
"Temp")
and not f.endswith(
"Iterator")\
657 and not f.endswith(
"Exception")
and\
658 f
not in modulename._raii_types
and \
659 f
not in modulename._plural_types:
660 if not hasattr(getattr(modulename, f),
'show'):
664 "All IMP classes should support show and __str__. The following "
665 "do not:\n%s\n If there is a good reason for them not to, add "
666 "them to the show_exceptions variable in the IMPModuleTest "
667 "call. Otherwise, please fix." %
"\n".join(not_found))
669 self.assertIn(e, all,
670 "Show exception "+e+
" is not a class in module")
671 self.assertTrue(
not hasattr(getattr(modulename, e),
'show'),
672 "Exception "+e+
" is not really a show exception")
675 """Run the named example script.
676 @return a dictionary of all the script's global variables.
677 This can be queried in a test case to make sure
678 the example performed correctly."""
684 path, name = os.path.split(filename)
685 oldsyspath = sys.path[:]
686 olssysargv = sys.argv[:]
687 sys.path.insert(0, path)
688 sys.argv = [filename]
692 exec(open(filename).read(), vars)
695 except SystemExit
as e:
696 if e.code != 0
and e.code
is not None:
698 "Example exit with code %s" % str(e.code))
702 sys.path = oldsyspath
703 sys.argv = olssysargv
705 return _ExecDictProxy(vars)
708 """Run a Python module as if with "python -m <modname>",
709 with the given list of arguments as sys.argv.
711 If module is an already-imported Python module, run its 'main'
712 function and return the result.
714 If module is a string, run the module in a subprocess and return
715 a subprocess.Popen-like object containing the child stdin,
718 def mock_setup_from_argv(*args, **kwargs):
721 if type(module) == type(os):
724 mod = __import__(module, {}, {}, [
''])
725 modpath = mod.__file__
726 if modpath.endswith(
'.pyc'):
727 modpath = modpath[:-1]
728 if type(module) == type(os):
729 old_sys_argv = sys.argv
731 old_setup = IMP.setup_from_argv
732 IMP.setup_from_argv = mock_setup_from_argv
734 sys.argv = [modpath] + args
737 IMP.setup_from_argv = old_setup
738 sys.argv = old_sys_argv
740 return _SubprocessWrapper(sys.executable, [modpath] + args)
743 """Check a Python module designed to be runnable with 'python -m'
744 to make sure it supports standard command line options."""
747 out, err = r.communicate()
748 self.assertEqual(r.returncode, 0)
749 self.assertNotEqual(err,
"")
750 self.assertEqual(out,
"")
753 class _ExecDictProxy(object):
754 """exec returns a Python dictionary, which contains IMP objects, other
755 Python objects, as well as base Python modules (such as sys and
756 __builtins__). If we just delete this dictionary, it is entirely
757 possible that base Python modules are removed from the dictionary
758 *before* some IMP objects. This will prevent the IMP objects' Python
759 destructors from running properly, so C++ objects will not be
760 cleaned up. This class proxies the base dict class, and on deletion
761 attempts to remove keys from the dictionary in an order that allows
762 IMP destructors to fire."""
763 def __init__(self, d):
768 module_type = type(IMP)
771 if type(d[k]) != module_type:
774 for meth
in [
'__contains__',
'__getitem__',
'__iter__',
'__len__',
775 'get',
'has_key',
'items',
'keys',
'values']:
776 exec(
"def %s(self, *args, **keys): "
777 "return self._d.%s(*args, **keys)" % (meth, meth))
780 class _TestResult(unittest.TextTestResult):
782 def __init__(self, stream=None, descriptions=None, verbosity=None):
783 super(_TestResult, self).__init__(stream, descriptions, verbosity)
786 def stopTestRun(self):
787 if 'IMP_TEST_DETAIL_DIR' in os.environ:
788 fname = os.path.join(os.environ[
'IMP_TEST_DETAIL_DIR'],
789 os.path.basename(sys.argv[0]))
790 with open(fname,
'wb')
as fh:
791 pickle.dump(self.all_tests, fh, -1)
792 super(_TestResult, self).stopTestRun()
794 def startTest(self, test):
795 super(_TestResult, self).startTest(test)
796 test.start_time = datetime.datetime.now()
798 def _test_finished(self, test, state, detail=None):
799 delta = datetime.datetime.now() - test.start_time
801 pv = delta.total_seconds()
802 except AttributeError:
803 pv = (float(delta.microseconds)
804 + (delta.seconds + delta.days * 24 * 3600) * 10**6) / 10**6
806 self.stream.write(
"in %.3fs ... " % pv)
807 if detail
is not None and not isinstance(detail, str):
808 detail = self._exc_info_to_string(detail, test)
809 test_doc = self.getDescription(test)
810 test_name = test.id()
811 if test_name.startswith(
'__main__.'):
812 test_name = test_name[9:]
813 self.all_tests.append({
'name': test_name,
814 'docstring': test_doc,
815 'time': pv,
'state': state,
'detail': detail})
817 def addSuccess(self, test):
818 self._test_finished(test,
'OK')
819 super(_TestResult, self).addSuccess(test)
821 def addError(self, test, err):
822 self._test_finished(test,
'ERROR', err)
823 super(_TestResult, self).addError(test, err)
825 def addFailure(self, test, err):
826 self._test_finished(test,
'FAIL', err)
827 super(_TestResult, self).addFailure(test, err)
829 def addSkip(self, test, reason):
830 self._test_finished(test,
'SKIP', reason)
831 super(_TestResult, self).addSkip(test, reason)
833 def addExpectedFailure(self, test, err):
834 self._test_finished(test,
'EXPFAIL', err)
835 super(_TestResult, self).addExpectedFailure(test, err)
837 def addUnexpectedSuccess(self, test):
838 self._test_finished(test,
'UNEXPSUC')
839 super(_TestResult, self).addUnexpectedSuccess(test)
841 def getDescription(self, test):
842 doc_first_line = test.shortDescription()
843 if self.descriptions
and doc_first_line:
844 return doc_first_line
849 class _TestRunner(unittest.TextTestRunner):
850 def _makeResult(self):
851 return _TestResult(self.stream, self.descriptions, self.verbosity)
855 """Run a set of tests; similar to unittest.main().
856 Obviates the need to separately import the 'unittest' module, and
857 ensures that main() is from the same unittest module that the
858 IMP.test testcases are. In addition, turns on some extra checks
859 (e.g. trying to use deprecated code will cause an exception
863 return unittest.main(testRunner=_TestRunner, *args, **keys)
866 class _SubprocessWrapper(subprocess.Popen):
867 def __init__(self, app, args, cwd=None):
870 if sys.platform ==
'win32' and app != sys.executable:
872 libdir = os.environ[
'PYTHONPATH'].split(
';')[0]
873 env = os.environ.copy()
874 env[
'PATH'] +=
';' + libdir
877 subprocess.Popen.__init__(self, [app]+list(args),
878 stdin=subprocess.PIPE,
879 stdout=subprocess.PIPE,
880 stderr=subprocess.PIPE, env=env, cwd=cwd,
881 universal_newlines=
True)
885 """Super class for simple IMP application test cases"""
886 def _get_application_file_name(self, filename):
889 if sys.platform ==
'win32':
894 """Run an application with the given list of arguments.
895 @return a subprocess.Popen-like object containing the child stdin,
898 filename = self._get_application_file_name(app)
899 if sys.platform ==
'win32':
901 return _SubprocessWrapper(os.path.join(os.environ[
'IMP_BIN_DIR'],
902 filename), args, cwd=cwd)
904 return _SubprocessWrapper(filename, args, cwd=cwd)
907 """Run a Python application with the given list of arguments.
908 The Python application should be self-runnable (i.e. it should
909 be executable and with a #! on the first line).
910 @return a subprocess.Popen-like object containing the child stdin,
914 if sys.executable !=
'/usr/bin/python' and 'IMP_BIN_DIR' in os.environ:
915 return _SubprocessWrapper(
917 [os.path.join(os.environ[
'IMP_BIN_DIR'], app)] + args)
919 return _SubprocessWrapper(app, args)
922 """Import an installed Python application, rather than running it.
923 This is useful to directly test components of the application.
924 @return the Python module object."""
926 import importlib.machinery
930 name = os.path.splitext(app)[0]
931 pathname = os.path.join(os.environ[
'IMP_BIN_DIR'], app)
933 return importlib.machinery.SourceFileLoader(name,
934 pathname).load_module()
936 return imp.load_source(name, pathname)
939 """Run an application with the given list of arguments.
940 @return a subprocess.Popen-like object containing the child stdin,
943 return _SubprocessWrapper(sys.executable, [app]+args)
946 """Assert that the application exited cleanly (return value = 0)."""
948 raise OSError(
"Application exited with signal %d\n" % -ret
953 "Application exited uncleanly, with exit code %d\n" % ret
957 """Read and return a set of shell commands from a doxygen file.
958 Each command is assumed to be in a \code{.sh}...\endcode block.
959 The doxygen file is specified relative to the test file itself.
960 This is used to make sure the commands shown in an application
961 example actually work (the testcase can also check the resulting
962 files for correctness)."""
963 def win32_normpath(p):
966 return " ".join([os.path.normpath(x)
for x
in p.split()])
968 def fix_win32_command(cmd):
970 if cmd.startswith(
'cp -r '):
971 return 'xcopy /E ' + win32_normpath(cmd[6:])
972 elif cmd.startswith(
'cp '):
973 return 'copy ' + win32_normpath(cmd[3:])
976 d = os.path.dirname(sys.argv[0])
977 doc = os.path.join(d, doxfile)
981 with open(doc)
as fh:
982 for line
in fh.readlines():
983 if '\code{.sh}' in line:
985 elif '\endcode' in line:
988 cmds.append(line.rstrip(
'\r\n').replace(
989 '<imp_example_path>', example_path))
990 if sys.platform ==
'win32':
991 cmds = [fix_win32_command(x)
for x
in cmds]
995 "Print and run a shell command, as returned by read_shell_commands()"
997 p = subprocess.call(cmd, shell=
True)
999 raise OSError(
"%s failed with exit value %d" % (cmd, p))
1003 """Check to make sure the number of C++ object references is as expected"""
1005 def __init__(self, testcase):
1009 IMP._director_objects.cleanup()
1010 self.__testcase = testcase
1012 self.__basenum = IMP.Object.get_number_of_live_objects()
1016 "Make sure that the number of references matches the expected value."
1018 IMP._director_objects.cleanup()
1021 if x
not in self.__names]
1022 newnum = IMP.Object.get_number_of_live_objects()-self.__basenum
1023 t.assertEqual(newnum, expected,
1024 "Number of objects don't match: "
1025 + str(newnum) +
" != " + str(expected) +
" found "
1030 """Check to make sure the number of director references is as expected"""
1032 def __init__(self, testcase):
1033 IMP._director_objects.cleanup()
1034 self.__testcase = testcase
1035 self.__basenum = IMP._director_objects.get_object_count()
1038 """Make sure that the number of references matches the expected value.
1039 If force_cleanup is set, clean up any unused references first before
1040 doing the assertion.
1044 IMP._director_objects.cleanup()
1045 t.assertEqual(IMP._director_objects.get_object_count()
1046 - self.__basenum, expected)
1055 if sys.platform ==
'win32' and 'PYTHONPATH' in os.environ \
1056 and 'IMP_BIN_DIR' in os.environ:
1057 libdir = os.environ[
'PYTHONPATH'].split(
';')[0]
1058 bindir = os.environ[
'IMP_BIN_DIR']
1059 path = os.environ[
'PATH']
1060 if libdir
not in path
or bindir
not in path:
1061 os.environ[
'PATH'] = bindir +
';' + libdir +
';' + path
1064 __version__ =
"2.16.0"
1067 '''Return the version of this module, as a string'''
1071 '''Return the fully-qualified name of this module'''
1075 '''Return the full path to one of this module's data files'''
1077 return IMP._get_module_data_path(
"test", fname)
1080 '''Return the full path to one of this module's example files'''
1082 return IMP._get_module_example_path(
"test", fname)
def run_python_module
Run a Python module as if with "python -m <modname>", with the given list of arguments as sys...
def temporary_working_directory
Simple context manager to run in a temporary directory.
def assertApplicationExitedCleanly
Assert that the application exited cleanly (return value = 0).
CheckLevel get_check_level()
Get the current audit mode.
def import_python_application
Import an installed Python application, rather than running it.
def open_input_file
Open and return an input file in the top-level test directory.
def run_application
Run an application with the given list of arguments.
def randomize_particles
Randomize the xyz coordinates of a list of particles.
def get_module_version
Return the version of this module, as a string.
A general exception for an internal error in IMP.
def main
Run a set of tests; similar to unittest.main().
An exception for an invalid usage of IMP.
Super class for simple IMP application test cases.
def assertRaisesInternalException
Assert that the given callable object raises InternalException.
def assert_number
Make sure that the number of references matches the expected value.
Check to make sure the number of director references is as expected.
def assertShow
Check that all the classes in modulename have a show method.
def get_data_path
Return the full path to one of this module's data files.
def get_example_path
Return the full path to one of this module's example files.
def run_shell_command
Print and run a shell command, as returned by read_shell_commands()
def assertRaisesUsageException
Assert that the given callable object raises UsageException.
Vector3D get_random_vector_in(const Cylinder3D &c)
Generate a random vector in a cylinder with uniform density.
def assertSequenceAlmostEqual
Fail if the difference between any two items in the two sequences are exceed the specified number of ...
Class for storing model, its restraints, constraints, and particles.
def run_python_application
Run a Python application with the given list of arguments.
def assert_number
Make sure that the number of references matches the expected value.
Strings get_live_object_names()
Return the names of all live objects.
def check_standard_object_methods
Check methods that every IMP::Object class should have.
def particle_distance
Return distance between two given particles.
def check_unary_function_deriv
Check the unary function func's derivatives against numerical approximations between lb and ub...
def get_tmp_file_name
Get the full name of an output file in the tmp directory.
Version and module information for Objects.
def run_example
Run the named example script.
def get_magnitude
Get the magnitude of a list of floats.
void set_deprecation_exceptions(bool tf)
Toggle whether an exception is thrown when a deprecated method is used.
def check_unary_function_min
Make sure that the minimum of the unary function func over the range between lb and ub is at expected...
def probabilistic_check
Help handle a test which is expected to fail some fraction of the time.
def create_particles_in_box
Create a bunch of particles in a box.
General purpose algebraic and geometric methods that are expected to be used by a wide variety of IMP...
def assertNotImplemented
Assert that the given callable object is not implemented.
The general base class for IMP exceptions.
def numerical_derivative
Calculate the derivative of the single-value function func at point val.
std::string get_example_path(std::string file_name)
Return the full path to one of this module's example files.
def xyz_numerical_derivatives
Calculate the x,y and z derivatives of the scoring function sf on the xyz particle.
def failure_probability
Estimate how likely a given block of code is to raise an AssertionError.
def assertClassNames
Check that all the classes in the module follow the IMP naming conventions.
def create_point_particle
Make a particle with optimizable x, y and z attributes, and add it to the model.
Class to handle individual particles of a Model object.
def read_shell_commands
Read and return a set of shell commands from a doxygen file.
Check to make sure the number of C++ object references is as expected.
def assertFunctionNames
Check that all the functions in the module follow the IMP naming conventions.
def assertValueObjects
Check that all the C++ classes in the module are values or objects.
def assertNumPyArrayEqual
Fail if the given numpy array doesn't match expected.
def get_module_name
Return the fully-qualified name of this module.
Super class for IMP test cases.
def assertXYZDerivativesInTolerance
Assert that x,y,z analytical derivatives match numerical within a tolerance, or a percentage (of the ...
def temporary_directory
Simple context manager to make a temporary directory.
def run_script
Run an application with the given list of arguments.
def get_input_file_name
Get the full name of an input file in the top-level test directory.
def check_runnable_python_module
Check a Python module designed to be runnable with 'python -m' to make sure it supports standard comm...
void set_check_level(CheckLevel tf)
Control runtime checks in the code.