1 """@namespace IMP::test
2 @brief Methods and classes for testing the IMP kernel and modules.
19 from unittest.util
import safe_repr
27 expectedFailure = unittest.expectedFailure
29 skipIf = unittest.skipIf
30 skipUnless = unittest.skipUnless
33 class _TempDir(object):
34 def __init__(self, dir=None):
35 self.tmpdir = tempfile.mkdtemp(dir=dir)
38 shutil.rmtree(self.tmpdir, ignore_errors=
True)
41 @contextlib.contextmanager
43 """Simple context manager to run in a temporary directory.
44 While the context manager is active (within the 'with' block)
45 the current working directory is set to a temporary directory.
46 When the context manager exists, the working directory is reset
47 and the temporary directory deleted."""
49 tmpdir = tempfile.mkdtemp()
53 shutil.rmtree(tmpdir, ignore_errors=
True)
56 @contextlib.contextmanager
58 """Simple context manager to make a temporary directory.
59 The temporary directory has the same lifetime as the context manager
60 (i.e. it is created at the start of the 'with' block, and deleted
61 at the end of the block).
62 @param dir If given, the temporary directory is made as a subdirectory
63 of that directory, rather than in the default temporary
64 directory location (e.g. /tmp)
65 @return the full path to the temporary directory.
67 tmpdir = tempfile.mkdtemp(dir=dir)
69 shutil.rmtree(tmpdir, ignore_errors=
True)
73 """Calculate the derivative of the single-value function `func` at
74 point `val`. The derivative is calculated using simple finite
75 differences starting with the given `step`; Richardson extrapolation
76 is then used to extrapolate the derivative at step=0."""
84 d = [[(f1 - f2) / (2.0 * step)]]
86 for i
in range(1, maxsteps):
87 d.append([0.] * (i + 1))
91 d[i][0] = (f1 - f2) / (2.0 * step)
93 for j
in range(1, i + 1):
94 d[i][j] = (d[i][j-1] * fac - d[i-1][j-1]) / (fac - 1.)
96 errt = max(abs(d[i][j] - d[i][j-1]),
97 abs(d[i][j] - d[i-1][j-1]))
101 if abs(d[i][i] - d[i-1][i-1]) >= safe * err:
104 raise ValueError(
"Cannot calculate numerical derivative")
109 """Calculate the x,y and z derivatives of the scoring function `sf`
110 on the `xyz` particle. The derivatives are approximated numerically
111 using the numerical_derivatives() function."""
112 class _XYZDerivativeFunc(object):
113 def __init__(self, sf, xyz, basis_vector):
116 self._basis_vector = basis_vector
117 self._starting_coordinates = xyz.get_coordinates()
119 def __call__(self, val):
120 self._xyz.set_coordinates(self._starting_coordinates +
121 self._basis_vector * val)
122 return self._sf.evaluate(
False)
127 for x
in ((1, 0, 0), (0, 1, 0), (0, 0, 1))])
131 """Super class for IMP test cases.
132 This provides a number of useful IMP-specific methods on top of
133 the standard Python `unittest.TestCase` class.
134 Test scripts should generally contain a subclass of this class,
135 conventionally called `Tests` (this makes it easier to run an
136 individual test from the command line) and use IMP::test::main()
137 as their main function."""
141 if not hasattr(unittest.TestCase,
'assertRegex'):
142 assertRegex = unittest.TestCase.assertRegexpMatches
143 assertNotRegex = unittest.TestCase.assertNotRegexpMatches
145 def __init__(self, *args, **keys):
146 unittest.TestCase.__init__(self, *args, **keys)
147 self._progname = os.path.abspath(sys.argv[0])
155 IMP.random_number_generator.seed(hash(time.time()) % 2**30)
161 if hasattr(self,
'_tmpdir'):
165 """Get the full name of an input file in the top-level
167 testdir = os.path.dirname(self._progname)
168 if self.__module__ !=
'__main__':
169 testdir = os.path.dirname(sys.modules[self.__module__].__file__)
170 dirs = testdir.split(os.path.sep)
171 for i
in range(len(dirs), 0, -1):
172 input = os.path.sep.join(dirs[:i] + [
'input'])
173 if os.path.isdir(input):
174 ret = os.path.join(input, filename)
175 if not os.path.exists(ret):
176 raise IOError(
"Test input file "+ret+
" does not exist")
178 raise IOError(
"No test input directory found")
181 """Open and return an input file in the top-level test directory."""
185 """Get the full name of an output file in the tmp directory.
186 The directory containing this file will be automatically
187 cleaned up when the test completes."""
188 if not hasattr(self,
'_tmpdir'):
189 self._tmpdir = _TempDir(os.environ.get(
'IMP_TMP_DIR'))
190 tmpdir = self._tmpdir.tmpdir
191 return os.path.join(tmpdir, filename)
194 """Get the magnitude of a list of floats"""
195 return sum([x*x
for x
in vector], 0)**.5
198 """Assert that the given callable object raises UsageException.
199 This differs from unittest's assertRaises in that the test
200 is skipped in fast mode (where usage checks are turned off)."""
205 """Assert that the given callable object raises InternalException.
206 This differs from unittest's assertRaises in that the test
207 is skipped in fast mode (where internal checks are turned off)."""
212 """Assert that the given callable object is not implemented."""
217 """Assert that x,y,z analytical derivatives match numerical within
218 a tolerance, or a percentage (of the analytical value), whichever
219 is larger. `sf` should be a ScoringFunction or Restraint,
220 although for backwards compatibility a Model is also accepted."""
222 derivs = xyz.get_derivatives()
224 pct = percentage / 100.0
225 self.assertAlmostEqual(
228 msg=
"Don't match "+str(derivs) + str(num_derivs))
229 self.assertAlmostEqual(derivs[0], num_derivs[0],
230 delta=max(tolerance, abs(derivs[0]) * pct))
231 self.assertAlmostEqual(derivs[1], num_derivs[1],
232 delta=max(tolerance, abs(derivs[1]) * pct))
233 self.assertAlmostEqual(derivs[2], num_derivs[2],
234 delta=max(tolerance, abs(derivs[2]) * pct))
238 """Fail if the difference between any two items in the two sequences
239 are exceed the specified number of places or delta. See
242 if delta
is not None and places
is not None:
243 raise TypeError(
"specify delta or places not both")
246 ftypename = ftype.__name__
248 stypename = stype.__name__
250 raise self.failureException(
251 'Sequences are of different types: %s != %s' % (
252 ftypename, stypename))
256 except (NotImplementedError, TypeError):
257 raise self.failureException(
258 'First %s has no length' % (ftypename))
261 except (NotImplementedError, TypeError):
262 raise self.failureException(
263 'Second %s has no length' % (stypename))
266 raise self.failureException(
267 'Sequences have non equal lengths: %d != %d' % (flen, slen))
270 for i
in range(min(flen, slen)):
271 differing =
'%ss differ: %s != %s\n' % (
272 ftypename.capitalize(), safe_repr(first),
277 except (TypeError, IndexError, NotImplementedError):
278 differing += (
'\nUnable to index element %d of first %s\n' %
284 except (TypeError, IndexError, NotImplementedError):
285 differing += (
'\nUnable to index element %d of second %s\n' %
290 self.assertAlmostEqual(
291 f, s, places=places, msg=msg, delta=delta)
292 except (TypeError, ValueError, NotImplementedError,
295 "\nFirst differing element "
296 "%d:\n%s\n%s\n") % (i, safe_repr(f), safe_repr(s))
301 standardMsg = differing
302 diffMsg =
'\n' +
'\n'.join(
303 difflib.ndiff(pprint.pformat(first).splitlines(),
304 pprint.pformat(second).splitlines()))
305 standardMsg = self._truncateMessage(standardMsg, diffMsg)
306 msg = self._formatMessage(msg, standardMsg)
307 raise self.failureException(msg)
310 """Make a particle with optimizable x, y and z attributes, and
311 add it to the model."""
319 """Help handle a test which is expected to fail some fraction of
320 the time. The test is run multiple times and an exception
321 is thrown only if it fails too many times.
322 @note Use of this function should be avoided. If there is a corner
323 case that results in a test 'occasionally' failing, write a
324 new test specifically for that corner case and assert that
325 it fails consistently (and remove the corner case from the
328 prob = chance_of_failure
332 prob = prob*chance_of_failure
333 for i
in range(0, tries):
341 raise AssertionError(
"Too many failures")
344 """Estimate how likely a given block of code is to raise an
348 while failures < 10
and tries < 1000:
354 return failures/tries
357 """Randomize the xyz coordinates of a list of particles"""
363 p.set_value(xkey, random.uniform(-deviation, deviation))
364 p.set_value(ykey, random.uniform(-deviation, deviation))
365 p.set_value(zkey, random.uniform(-deviation, deviation))
368 """Return distance between two given particles"""
372 dx = p1.get_value(xkey) - p2.get_value(xkey)
373 dy = p1.get_value(ykey) - p2.get_value(ykey)
374 dz = p1.get_value(zkey) - p2.get_value(zkey)
375 return math.sqrt(dx*dx + dy*dy + dz*dz)
378 """Check the unary function func's derivatives against numerical
379 approximations between lb and ub"""
380 for f
in [lb + i * step
for i
in range(1, int((ub-lb)/step))]:
381 (v, d) = func.evaluate_with_derivative(f)
383 self.assertAlmostEqual(d, da, delta=max(abs(.1 * d), 0.01))
386 """Make sure that the minimum of the unary function func over the
387 range between lb and ub is at expected_fmin"""
388 fmin, vmin = lb, func.evaluate(lb)
389 for f
in [lb + i * step
for i
in range(1, int((ub-lb)/step))]:
393 self.assertAlmostEqual(fmin, expected_fmin, delta=step)
396 """Check methods that every IMP::Object class should have"""
397 obj.set_was_used(
True)
400 self.assertIsNotNone(cls.get_from(obj))
401 self.assertRaises(ValueError, cls.get_from,
IMP.Model())
403 self.assertIsInstance(str(obj), str)
404 self.assertIsInstance(repr(obj), str)
406 verinf = obj.get_version_info()
415 """Create a bunch of particles in a box"""
420 for i
in range(0, num):
427 def _get_type(self, module, name):
428 return eval(
'type('+module+
"."+name+
')')
431 "Check that all the C++ classes in the module are values or objects."
433 ok = set(exceptions_list + module._value_types + module._object_types
434 + module._raii_types + module._plural_types)
438 if self._get_type(module.__name__, name) == type \
439 and not name.startswith(
"_"):
440 if name.find(
"SwigPyIterator") != -1:
443 if not eval(
'hasattr(%s.%s, "__swig_destroy__")'
444 % (module.__name__, name)):
451 "All IMP classes should be labeled as values or objects to get "
452 "memory management correct in Python. The following are not:\n%s\n"
453 "Please add an IMP_SWIG_OBJECT or IMP_SWIG_VALUE call to the "
454 "Python wrapper, or if the class has a good reason to be "
455 "neither, add the name to the value_object_exceptions list in "
456 "the IMPModuleTest call." % str(bad))
457 for e
in exceptions_list:
459 e
not in module._value_types + module._object_types
460 + module._raii_types + module._plural_types,
461 "Value/Object exception "+e+
" is not an exception")
463 def _check_spelling(self, word, words):
464 """Check that the word is spelled correctly"""
465 if "words" not in dir(self):
467 wordlist = fh.read().split("\n")
469 custom_words = [
"info",
"prechange",
"int",
"ints",
"optimizeds",
470 "graphviz",
"voxel",
"voxels",
"endian",
'rna',
471 'dna',
"xyzr",
"pdbs",
"fft",
"ccc",
"gaussian"]
474 exclude_words = set([
"adapter",
"grey"])
475 self.words = set(wordlist+custom_words) - exclude_words
477 for i
in "0123456789":
482 if word
in self.words:
490 """Check that all the classes in the module follow the IMP
491 naming conventions."""
495 cc = re.compile(
"([A-Z][a-z]*)")
497 if self._get_type(module.__name__, name) == type \
498 and not name.startswith(
"_"):
499 if name.find(
"SwigPyIterator") != -1:
501 for t
in re.findall(cc, name):
502 if not self._check_spelling(t.lower(), words):
503 misspelled.append(t.lower())
508 "All IMP classes should be properly spelled. The following "
509 "are not: %s.\nMisspelled words: %s. Add words to the "
510 "spelling_exceptions variable of the IMPModuleTest if needed."
511 % (str(bad),
", ".join(set(misspelled))))
514 if self._get_type(module.__name__, name) == type \
515 and not name.startswith(
"_"):
516 if name.find(
"SwigPyIterator") != -1:
518 if name.find(
'_') != -1:
520 if name.lower == name:
522 for t
in re.findall(cc, name):
523 if not self._check_spelling(t.lower(), words):
524 print(
"misspelled %s in %s" % (t, name))
528 "All IMP classes should have CamelCase names. The following "
529 "do not: %s." %
"\n".join(bad))
531 def _check_function_name(self, prefix, name, verbs, all, exceptions, words,
534 fullname = prefix+
"."+name
538 'unprotected_evaluate',
"unprotected_evaluate_if_good",
539 "unprotected_evaluate_if_below",
540 "after_evaluate",
"before_evaluate",
"has_attribute",
541 "decorate_particle",
"particle_is_instance"]
542 if name
in old_exceptions:
544 if fullname
in exceptions:
546 if name.endswith(
"swigregister"):
548 if name.lower() != name:
549 if name[0].lower() != name[0]
and name.split(
'_')[0]
in all:
554 tokens = name.split(
"_")
555 if tokens[0]
not in verbs:
558 if not self._check_spelling(t, words):
560 print(
"misspelled %s in %s" % (t, name))
564 def _static_method(self, module, prefix, name):
565 """For static methods of the form Foo.bar SWIG creates free functions
566 named Foo_bar. Exclude these from spelling checks since the method
567 Foo.bar has already been checked."""
568 if prefix
is None and '_' in name:
569 modobj = eval(module)
570 cls, meth = name.split(
'_', 1)
571 if hasattr(modobj, cls):
572 clsobj = eval(module +
'.' + cls)
573 if hasattr(clsobj, meth):
576 def _check_function_names(self, module, prefix, names, verbs, all,
577 exceptions, words, misspelled):
580 typ = self._get_type(module, name)
581 if name.startswith(
"_")
or name ==
"weakref_proxy":
583 if typ
in (types.BuiltinMethodType, types.MethodType) \
584 or (typ == types.FunctionType
and
585 not self._static_method(module, prefix, name)):
586 bad.extend(self._check_function_name(prefix, name, verbs, all,
589 if typ == type
and "SwigPyIterator" not in name:
590 members = eval(
"dir("+module+
"."+name+
")")
591 bad.extend(self._check_function_names(module+
"."+name,
592 name, members, verbs, [],
598 """Check that all the functions in the module follow the IMP
599 naming conventions."""
601 verbs = set([
"add",
"remove",
"get",
"set",
"evaluate",
"compute",
602 "show",
"create",
"destroy",
"push",
"pop",
"write",
603 "read",
"do",
"show",
"load",
"save",
"reset",
"accept",
604 "reject",
"clear",
"handle",
"update",
"apply",
605 "optimize",
"reserve",
"dump",
"propose",
"setup",
606 "teardown",
"visit",
"find",
"run",
"swap",
"link",
609 bad = self._check_function_names(module.__name__,
None, all, verbs,
610 all, exceptions, words, misspelled)
611 message = (
"All IMP methods and functions should have lower case "
612 "names separated by underscores and beginning with a "
613 "verb, preferably one of ['add', 'remove', 'get', 'set', "
614 "'create', 'destroy']. Each of the words should be a "
615 "properly spelled English word. The following do not "
616 "(given our limited list of verbs that we check for):\n"
617 "%(bad)s\nIf there is a good reason for them not to "
618 "(eg it does start with a verb, just one with a meaning "
619 "that is not covered by the normal list), add them to the "
620 "function_name_exceptions variable in the "
621 "standards_exceptions file. Otherwise, please fix. "
622 "The current verb list is %(verbs)s"
623 % {
"bad":
"\n".join(bad),
"verbs": verbs})
624 if len(misspelled) > 0:
625 message +=
"\nMisspelled words: " +
", ".join(set(misspelled)) \
626 +
". Add words to the spelling_exceptions variable " \
627 +
"of the standards_exceptions file if needed."
628 self.assertEqual(len(bad), 0, message)
631 """Check that all the classes in modulename have a show method"""
632 all = dir(modulename)
639 if not eval(
'hasattr(%s.%s, "__swig_destroy__")'
640 % (modulename.__name__, f)):
642 if self._get_type(modulename.__name__, f) == type \
643 and not f.startswith(
"_") \
644 and not f.endswith(
"_swigregister")\
645 and f
not in exceptions\
646 and not f.endswith(
"Temp")
and not f.endswith(
"Iterator")\
647 and not f.endswith(
"Exception")
and\
648 f
not in modulename._raii_types
and \
649 f
not in modulename._plural_types:
650 if not hasattr(getattr(modulename, f),
'show'):
654 "All IMP classes should support show and __str__. The following "
655 "do not:\n%s\n If there is a good reason for them not to, add "
656 "them to the show_exceptions variable in the IMPModuleTest "
657 "call. Otherwise, please fix." %
"\n".join(not_found))
659 self.assertIn(e, all,
660 "Show exception "+e+
" is not a class in module")
661 self.assertTrue(
not hasattr(getattr(modulename, e),
'show'),
662 "Exception "+e+
" is not really a show exception")
665 """Run the named example script.
666 @return a dictionary of all the script's global variables.
667 This can be queried in a test case to make sure
668 the example performed correctly."""
674 path, name = os.path.split(filename)
675 oldsyspath = sys.path[:]
676 olssysargv = sys.argv[:]
677 sys.path.insert(0, path)
678 sys.argv = [filename]
682 exec(open(filename).read(), vars)
685 except SystemExit
as e:
686 if e.code != 0
and e.code
is not None:
688 "Example exit with code %s" % str(e.code))
692 sys.path = oldsyspath
693 sys.argv = olssysargv
695 return _ExecDictProxy(vars)
698 """Run a Python module as if with "python -m <modname>",
699 with the given list of arguments as sys.argv.
701 If module is an already-imported Python module, run its 'main'
702 function and return the result.
704 If module is a string, run the module in a subprocess and return
705 a subprocess.Popen-like object containing the child stdin,
708 def mock_setup_from_argv(*args, **kwargs):
711 if type(module) == type(os):
714 mod = __import__(module, {}, {}, [
''])
715 modpath = mod.__file__
716 if modpath.endswith(
'.pyc'):
717 modpath = modpath[:-1]
718 if type(module) == type(os):
719 old_sys_argv = sys.argv
721 old_setup = IMP.setup_from_argv
722 IMP.setup_from_argv = mock_setup_from_argv
724 sys.argv = [modpath] + args
727 IMP.setup_from_argv = old_setup
728 sys.argv = old_sys_argv
730 return _SubprocessWrapper(sys.executable, [modpath] + args)
733 """Check a Python module designed to be runnable with 'python -m'
734 to make sure it supports standard command line options."""
737 out, err = r.communicate()
738 self.assertEqual(r.returncode, 0)
739 self.assertNotEqual(err,
"")
740 self.assertEqual(out,
"")
743 class _ExecDictProxy(object):
744 """exec returns a Python dictionary, which contains IMP objects, other
745 Python objects, as well as base Python modules (such as sys and
746 __builtins__). If we just delete this dictionary, it is entirely
747 possible that base Python modules are removed from the dictionary
748 *before* some IMP objects. This will prevent the IMP objects' Python
749 destructors from running properly, so C++ objects will not be
750 cleaned up. This class proxies the base dict class, and on deletion
751 attempts to remove keys from the dictionary in an order that allows
752 IMP destructors to fire."""
753 def __init__(self, d):
758 module_type = type(IMP)
761 if type(d[k]) != module_type:
764 for meth
in [
'__contains__',
'__getitem__',
'__iter__',
'__len__',
765 'get',
'has_key',
'items',
'keys',
'values']:
766 exec(
"def %s(self, *args, **keys): "
767 "return self._d.%s(*args, **keys)" % (meth, meth))
770 class _TestResult(unittest.TextTestResult):
772 def __init__(self, stream=None, descriptions=None, verbosity=None):
773 super(_TestResult, self).__init__(stream, descriptions, verbosity)
776 def stopTestRun(self):
777 if 'IMP_TEST_DETAIL_DIR' in os.environ:
778 fname = os.path.join(os.environ[
'IMP_TEST_DETAIL_DIR'],
779 os.path.basename(sys.argv[0]))
780 with open(fname,
'wb')
as fh:
781 pickle.dump(self.all_tests, fh, -1)
782 super(_TestResult, self).stopTestRun()
784 def startTest(self, test):
785 super(_TestResult, self).startTest(test)
786 test.start_time = datetime.datetime.now()
788 def _test_finished(self, test, state, detail=None):
789 delta = datetime.datetime.now() - test.start_time
791 pv = delta.total_seconds()
792 except AttributeError:
793 pv = (float(delta.microseconds)
794 + (delta.seconds + delta.days * 24 * 3600) * 10**6) / 10**6
796 self.stream.write(
"in %.3fs ... " % pv)
797 if detail
is not None and not isinstance(detail, str):
798 detail = self._exc_info_to_string(detail, test)
799 test_doc = self.getDescription(test)
800 test_name = test.id()
801 if test_name.startswith(
'__main__.'):
802 test_name = test_name[9:]
803 self.all_tests.append({
'name': test_name,
804 'docstring': test_doc,
805 'time': pv,
'state': state,
'detail': detail})
807 def addSuccess(self, test):
808 self._test_finished(test,
'OK')
809 super(_TestResult, self).addSuccess(test)
811 def addError(self, test, err):
812 self._test_finished(test,
'ERROR', err)
813 super(_TestResult, self).addError(test, err)
815 def addFailure(self, test, err):
816 self._test_finished(test,
'FAIL', err)
817 super(_TestResult, self).addFailure(test, err)
819 def addSkip(self, test, reason):
820 self._test_finished(test,
'SKIP', reason)
821 super(_TestResult, self).addSkip(test, reason)
823 def addExpectedFailure(self, test, err):
824 self._test_finished(test,
'EXPFAIL', err)
825 super(_TestResult, self).addExpectedFailure(test, err)
827 def addUnexpectedSuccess(self, test):
828 self._test_finished(test,
'UNEXPSUC')
829 super(_TestResult, self).addUnexpectedSuccess(test)
831 def getDescription(self, test):
832 doc_first_line = test.shortDescription()
833 if self.descriptions
and doc_first_line:
834 return doc_first_line
839 class _TestRunner(unittest.TextTestRunner):
840 def _makeResult(self):
841 return _TestResult(self.stream, self.descriptions, self.verbosity)
845 """Run a set of tests; similar to unittest.main().
846 Obviates the need to separately import the 'unittest' module, and
847 ensures that main() is from the same unittest module that the
848 IMP.test testcases are. In addition, turns on some extra checks
849 (e.g. trying to use deprecated code will cause an exception
853 return unittest.main(testRunner=_TestRunner, *args, **keys)
856 class _SubprocessWrapper(subprocess.Popen):
857 def __init__(self, app, args, cwd=None):
860 if sys.platform ==
'win32' and app != sys.executable:
862 libdir = os.environ[
'PYTHONPATH'].split(
';')[0]
863 env = os.environ.copy()
864 env[
'PATH'] +=
';' + libdir
867 subprocess.Popen.__init__(self, [app]+list(args),
868 stdin=subprocess.PIPE,
869 stdout=subprocess.PIPE,
870 stderr=subprocess.PIPE, env=env, cwd=cwd,
871 universal_newlines=
True)
875 """Super class for simple IMP application test cases"""
876 def _get_application_file_name(self, filename):
879 if sys.platform ==
'win32':
884 """Run an application with the given list of arguments.
885 @return a subprocess.Popen-like object containing the child stdin,
888 filename = self._get_application_file_name(app)
889 if sys.platform ==
'win32':
891 return _SubprocessWrapper(os.path.join(os.environ[
'IMP_BIN_DIR'],
892 filename), args, cwd=cwd)
894 return _SubprocessWrapper(filename, args, cwd=cwd)
897 """Run a Python application with the given list of arguments.
898 The Python application should be self-runnable (i.e. it should
899 be executable and with a #! on the first line).
900 @return a subprocess.Popen-like object containing the child stdin,
904 if sys.executable !=
'/usr/bin/python' and 'IMP_BIN_DIR' in os.environ:
905 return _SubprocessWrapper(
907 [os.path.join(os.environ[
'IMP_BIN_DIR'], app)] + args)
909 return _SubprocessWrapper(app, args)
912 """Import an installed Python application, rather than running it.
913 This is useful to directly test components of the application.
914 @return the Python module object."""
916 import importlib.machinery
920 name = os.path.splitext(app)[0]
921 pathname = os.path.join(os.environ[
'IMP_BIN_DIR'], app)
923 return importlib.machinery.SourceFileLoader(name,
924 pathname).load_module()
926 return imp.load_source(name, pathname)
929 """Run an application with the given list of arguments.
930 @return a subprocess.Popen-like object containing the child stdin,
933 return _SubprocessWrapper(sys.executable, [app]+args)
936 """Assert that the application exited cleanly (return value = 0)."""
938 raise OSError(
"Application exited with signal %d\n" % -ret
943 "Application exited uncleanly, with exit code %d\n" % ret
947 """Read and return a set of shell commands from a doxygen file.
948 Each command is assumed to be in a \code{.sh}...\endcode block.
949 The doxygen file is specified relative to the test file itself.
950 This is used to make sure the commands shown in an application
951 example actually work (the testcase can also check the resulting
952 files for correctness)."""
953 def win32_normpath(p):
956 return " ".join([os.path.normpath(x)
for x
in p.split()])
958 def fix_win32_command(cmd):
960 if cmd.startswith(
'cp -r '):
961 return 'xcopy /E ' + win32_normpath(cmd[6:])
962 elif cmd.startswith(
'cp '):
963 return 'copy ' + win32_normpath(cmd[3:])
966 d = os.path.dirname(sys.argv[0])
967 doc = os.path.join(d, doxfile)
971 with open(doc)
as fh:
972 for line
in fh.readlines():
973 if '\code{.sh}' in line:
975 elif '\endcode' in line:
978 cmds.append(line.rstrip(
'\r\n').replace(
979 '<imp_example_path>', example_path))
980 if sys.platform ==
'win32':
981 cmds = [fix_win32_command(x)
for x
in cmds]
985 "Print and run a shell command, as returned by read_shell_commands()"
987 p = subprocess.call(cmd, shell=
True)
989 raise OSError(
"%s failed with exit value %d" % (cmd, p))
993 """Check to make sure the number of C++ object references is as expected"""
995 def __init__(self, testcase):
999 IMP._director_objects.cleanup()
1000 self.__testcase = testcase
1002 self.__basenum = IMP.Object.get_number_of_live_objects()
1006 "Make sure that the number of references matches the expected value."
1008 IMP._director_objects.cleanup()
1011 if x
not in self.__names]
1012 newnum = IMP.Object.get_number_of_live_objects()-self.__basenum
1013 t.assertEqual(newnum, expected,
1014 "Number of objects don't match: "
1015 + str(newnum) +
" != " + str(expected) +
" found "
1020 """Check to make sure the number of director references is as expected"""
1022 def __init__(self, testcase):
1023 IMP._director_objects.cleanup()
1024 self.__testcase = testcase
1025 self.__basenum = IMP._director_objects.get_object_count()
1028 """Make sure that the number of references matches the expected value.
1029 If force_cleanup is set, clean up any unused references first before
1030 doing the assertion.
1034 IMP._director_objects.cleanup()
1035 t.assertEqual(IMP._director_objects.get_object_count()
1036 - self.__basenum, expected)
1045 if sys.platform ==
'win32' and 'PYTHONPATH' in os.environ \
1046 and 'IMP_BIN_DIR' in os.environ:
1047 libdir = os.environ[
'PYTHONPATH'].split(
';')[0]
1048 bindir = os.environ[
'IMP_BIN_DIR']
1049 path = os.environ[
'PATH']
1050 if libdir
not in path
or bindir
not in path:
1051 os.environ[
'PATH'] = bindir +
';' + libdir +
';' + path
1054 __version__ =
"2.15.0"
1057 '''Return the version of this module, as a string'''
1061 '''Return the fully-qualified name of this module'''
1065 '''Return the full path to one of this module's data files'''
1067 return IMP._get_module_data_path(
"test", fname)
1070 '''Return the full path to one of this module's example files'''
1072 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 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.