1 """@namespace IMP::test
2 @brief Methods and classes for testing the IMP kernel and modules.
18 from .
import _compat_python
19 from ._compat_python
import unittest2
20 from ._compat_python.unittest2.util
import safe_repr
29 def __load_unittest_package():
31 for modname, fromlist
in ((
'unittest', []),
35 u = __import__(modname, {}, {}, fromlist)
36 if hasattr(u,
'skip'):
39 errors.append(
"'%s' does not have the 'skip' decorator" \
41 except ImportError
as e:
44 return _compat_python.unittest2
45 raise ImportError(
"IMP.test requires a newer version of Python's unittest "
46 "package than is available. Either upgrade to a new "
47 "enough Python (at least 2.7 or 3.2) or install the "
48 "unittest2 package. Encountered errors: %s" \
50 unittest = __load_unittest_package()
53 expectedFailure = unittest.expectedFailure
55 skipIf = unittest.skipIf
56 skipUnless = unittest.skipUnless
58 class _TempDir(object):
59 def __init__(self, dir=None):
60 self.tmpdir = tempfile.mkdtemp(dir=dir)
62 shutil.rmtree(self.tmpdir, ignore_errors=
True)
64 @contextlib.contextmanager
66 """Simple context manager to run in a temporary directory.
67 While the context manager is active (within the 'with' block)
68 the current working directory is set to a temporary directory.
69 When the context manager exists, the working directory is reset
70 and the temporary directory deleted."""
72 tmpdir = tempfile.mkdtemp()
76 shutil.rmtree(tmpdir, ignore_errors=
True)
78 @contextlib.contextmanager
80 """Simple context manager to make a temporary directory.
81 The temporary directory has the same lifetime as the context manager
82 (i.e. it is created at the start of the 'with' block, and deleted
83 at the end of the block).
84 @param dir If given, the temporary directory is made as a subdirectory
85 of that directory, rather than in the default temporary
86 directory location (e.g. /tmp)
87 @return the full path to the temporary directory.
89 tmpdir = tempfile.mkdtemp(dir=dir)
91 shutil.rmtree(tmpdir, ignore_errors=
True)
94 """Calculate the derivative of the single-value function `func` at
95 point `val`. The derivative is calculated using simple finite
96 differences starting with the given `step`; Richardson extrapolation
97 is then used to extrapolate the derivative at step=0."""
102 f1 = func(val + step)
103 f2 = func(val - step)
105 d = [[(f1 - f2) / (2.0 * step)]]
107 for i
in range(1, maxsteps):
108 d.append([0.] * (i + 1))
110 f1 = func(val + step)
111 f2 = func(val - step)
112 d[i][0] = (f1 - f2) / (2.0 * step)
114 for j
in range(1, i + 1):
115 d[i][j] = (d[i][j-1] * fac - d[i-1][j-1]) / (fac - 1.)
117 errt = max(abs(d[i][j] - d[i][j-1]),
118 abs(d[i][j] - d[i-1][j-1]))
122 if abs(d[i][i] - d[i-1][i-1]) >= safe * err:
125 raise ValueError(
"Cannot calculate numerical derivative")
130 """Calculate the x,y and z derivatives of the scoring function `sf`
131 on the `xyz` particle. The derivatives are approximated numerically
132 using the numerical_derivatives() function."""
133 class _XYZDerivativeFunc(object):
134 def __init__(self, sf, xyz, basis_vector):
137 self._basis_vector = basis_vector
138 self._starting_coordinates = xyz.get_coordinates()
140 def __call__(self, val):
141 self._xyz.set_coordinates(self._starting_coordinates + \
142 self._basis_vector * val)
143 return self._sf.evaluate(
False)
147 for x
in ((1,0,0), (0,1,0), (0,0,1))])
151 """Super class for IMP test cases.
152 This provides a number of useful IMP-specific methods on top of
153 the standard Python `unittest.TestCase` class.
154 Test scripts should generally contain a subclass of this class,
155 conventionally called `Tests` (this makes it easier to run an
156 individual test from the command line) and use IMP::test::main()
157 as their main function."""
161 if not hasattr(unittest.TestCase,
'assertRegex'):
162 assertRegex = unittest.TestCase.assertRegexpMatches
163 assertNotRegex = unittest.TestCase.assertNotRegexpMatches
165 def __init__(self, *args, **keys):
166 unittest.TestCase.__init__(self, *args, **keys)
167 self._progname = os.path.abspath(sys.argv[0])
175 IMP.random_number_generator.seed(hash(time.time())%2**30)
181 if hasattr(self,
'_tmpdir'):
185 """Get the full name of an input file in the top-level
187 testdir = os.path.dirname(self._progname)
188 if self.__module__ !=
'__main__':
189 testdir = os.path.dirname(sys.modules[self.__module__].__file__)
190 dirs = testdir.split(os.path.sep)
191 for i
in range(len(dirs), 0, -1):
192 input = os.path.sep.join(dirs[:i] + [
'input'])
193 if os.path.isdir(input):
194 ret = os.path.join(input, filename)
195 if not os.path.exists(ret):
196 raise IOError(
"Test input file "+ret+
" does not exist")
198 raise IOError(
"No test input directory found")
201 """Open and return an input file in the top-level test directory."""
205 """Get the full name of an output file in the tmp directory.
206 The directory containing this file will be automatically
207 cleaned up when the test completes."""
208 if not hasattr(self,
'_tmpdir'):
209 self._tmpdir = _TempDir(os.environ.get(
'IMP_TMP_DIR'))
210 tmpdir = self._tmpdir.tmpdir
211 return os.path.join(tmpdir, filename)
214 """Get the magnitude of a list of floats"""
215 return sum([x*x
for x
in vector], 0)**.5
218 """Assert that the given callable object raises UsageException.
219 This differs from unittest's assertRaises in that the test
220 is skipped in fast mode (where usage checks are turned off)."""
225 """Assert that the given callable object raises InternalException.
226 This differs from unittest's assertRaises in that the test
227 is skipped in fast mode (where internal checks are turned off)."""
232 """Assert that the given callable object is not implemented."""
237 """Assert that x,y,z analytical derivatives match numerical within
238 a tolerance, or a percentage (of the analytical value), whichever
239 is larger. `sf` should be a ScoringFunction or Restraint,
240 although for backwards compatibility a Model is also accepted."""
242 derivs = xyz.get_derivatives()
244 pct = percentage / 100.0
245 self.assertAlmostEqual(self.
get_magnitude(derivs-num_derivs),0,
247 msg=
"Don't match "+str(derivs) + str(num_derivs))
248 self.assertAlmostEqual(derivs[0], num_derivs[0],
249 delta=max(tolerance, abs(derivs[0]) * pct))
250 self.assertAlmostEqual(derivs[1], num_derivs[1],
251 delta=max(tolerance, abs(derivs[1]) * pct))
252 self.assertAlmostEqual(derivs[2], num_derivs[2],
253 delta=max(tolerance, abs(derivs[2]) * pct))
257 """Fail if the difference between any two items in the two sequences
258 are exceed the specified number of places or delta. See
261 if delta
is not None and places
is not None:
262 raise TypeError(
"specify delta or places not both")
265 ftypename = ftype.__name__
267 stypename = stype.__name__
269 raise self.failureException(
270 'Sequences are of different types: %s != %s' % (
271 ftypename, stypename))
275 except (NotImplementedError, TypeError):
276 raise self.failureException(
277 'First %s has no length' % (ftypename))
280 except (NotImplementedError, TypeError):
281 raise self.failureException(
282 'Second %s has no length' % (stypename))
285 raise self.failureException(
286 'Sequences have non equal lengths: %d != %d' % (flen, slen))
289 for i
in range(min(flen, slen)):
290 differing =
'%ss differ: %s != %s\n' % (
291 ftypename.capitalize(), safe_repr(first),
296 except (TypeError, IndexError, NotImplementedError):
297 differing += (
'\nUnable to index element %d of first %s\n' %
303 except (TypeError, IndexError, NotImplementedError):
304 differing += (
'\nUnable to index element %d of second %s\n' %
309 self.assertAlmostEqual(
310 f, s, places=places, msg=msg, delta=delta)
311 except (TypeError, ValueError, NotImplementedError, AssertionError):
313 "\nFirst differing element "
314 "%d:\n%s\n%s\n") % (i, safe_repr(f), safe_repr(s))
319 standardMsg = differing
320 diffMsg =
'\n' +
'\n'.join(
321 difflib.ndiff(pprint.pformat(first).splitlines(),
322 pprint.pformat(second).splitlines()))
323 standardMsg = self._truncateMessage(standardMsg, diffMsg)
324 msg = self._formatMessage(msg, standardMsg)
325 raise self.failureException(msg)
328 """Make a particle with optimizable x, y and z attributes, and
329 add it to the model."""
337 """Help handle a test which is expected to fail some fraction of
338 the time. The test is run multiple times and an exception
339 is thrown only if it fails too many times.
340 @note Use of this function should be avoided. If there is a corner
341 case that results in a test 'occasionally' failing, write a
342 new test specifically for that corner case and assert that
343 it fails consistently (and remove the corner case from the
346 prob=chance_of_failure
350 prob= prob*chance_of_failure
351 for i
in range(0, tries):
359 raise AssertError(
"Too many failures")
362 """Estimate how likely a given block of code is to raise an
366 while failures < 10
and tries <1000:
372 return failures/tries
375 """Randomize the xyz coordinates of a list of particles"""
381 p.set_value(xkey, random.uniform(-deviation, deviation))
382 p.set_value(ykey, random.uniform(-deviation, deviation))
383 p.set_value(zkey, random.uniform(-deviation, deviation))
386 """Return distance between two given particles"""
390 dx = p1.get_value(xkey) - p2.get_value(xkey)
391 dy = p1.get_value(ykey) - p2.get_value(ykey)
392 dz = p1.get_value(zkey) - p2.get_value(zkey)
393 return math.sqrt(dx*dx + dy*dy + dz*dz)
396 """Check the unary function func's derivatives against numerical
397 approximations between lb and ub"""
398 for f
in [lb + i * step
for i
in range(1, int((ub-lb)/step))]:
399 (v,d)= func.evaluate_with_derivative(f)
401 self.assertAlmostEqual(d, da, delta=max(abs(.1 *d), 0.01))
404 """Make sure that the minimum of the unary function func over the
405 range between lb and ub is at expected_fmin"""
406 fmin, vmin = lb, func.evaluate(lb)
407 for f
in [lb + i * step
for i
in range(1, int((ub-lb)/step))]:
411 self.assertAlmostEqual(fmin, expected_fmin, delta=step)
414 """Check methods that every IMP::Object class should have"""
415 obj.set_was_used(
True)
418 self.assertIsNotNone(cls.get_from(obj))
419 self.assertRaises(ValueError, cls.get_from,
IMP.Model())
421 self.assertIsInstance(str(obj), str)
422 self.assertIsInstance(repr(obj), str)
424 verinf = obj.get_version_info()
433 """Create a bunch of particles in a box"""
438 for i
in range(0,num):
443 def _get_type(self, module, name):
444 return eval(
'type('+module+
"."+name+
')')
446 "Check that all the C++ classes in the module are values or objects."
448 ok = set(exceptions_list + module._value_types + module._object_types + module._raii_types + module._plural_types)
452 if self._get_type(module.__name__, name)==type
and not name.startswith(
"_"):
453 if name.find(
"SwigPyIterator") != -1:
456 if not eval(
'hasattr(%s.%s, "__swig_destroy__")' \
457 % (module.__name__, name)):
462 message=
"All IMP classes should be labeled as values or 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." \
464 self.assertEqual(len(bad), 0, message)
465 for e
in exceptions_list:
466 self.assertTrue(e
not in module._value_types
467 + module._object_types
469 + module._plural_types,
470 "Value/Object exception "+e+
" is not an exception")
472 def _check_spelling(self, word, words):
473 """Check that the word is spelled correctly"""
474 if "words" not in dir(self):
476 wordlist= fh.read().split("\n")
478 custom_words=[
"info",
"prechange",
"int",
"ints",
"optimizeds",
"graphviz",
479 "voxel",
"voxels",
"endian",
'rna',
'dna',
480 "xyzr",
"pdbs",
"fft",
"ccc",
"gaussian"]
483 exclude_words = set([
"adapter",
"grey"])
484 self.words=set(wordlist+custom_words) - exclude_words
486 for i
in "0123456789":
491 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
and not name.startswith(
"_"):
506 if name.find(
"SwigPyIterator") != -1:
508 for t
in re.findall(cc, name):
509 if not self._check_spelling(t.lower(), words):
510 misspelled.append(t.lower())
513 self.assertEqual(len(bad), 0,
514 "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." \
515 % (str(bad),
", ".join(set(misspelled))))
518 if self._get_type(module.__name__, name)==type
and not name.startswith(
"_"):
519 if name.find(
"SwigPyIterator") != -1:
521 if name.find(
'_') != -1:
523 if name.lower== name:
525 for t
in re.findall(cc, name):
526 if not self._check_spelling(t.lower(), words):
527 print(
"misspelled %s in %s" % (t, name))
529 message=
"All IMP classes should have CamelCase names. The following do not: %s." \
531 self.assertEqual(len(bad), 0, message)
533 def _check_function_name(self, prefix, name, verbs, all, exceptions, words,
536 fullname=prefix+
"."+name
539 old_exceptions=[
'unprotected_evaluate',
"unprotected_evaluate_if_good",
540 "unprotected_evaluate_if_below",
541 "after_evaluate",
"before_evaluate",
"has_attribute",
542 "decorate_particle",
"particle_is_instance"]
543 if name
in old_exceptions:
546 if fullname
in exceptions:
548 if name.endswith(
"swigregister"):
550 if name.lower() != name:
551 if name[0].lower() != name[0]
and name.split(
'_')[0]
in all:
556 tokens= name.split(
"_")
557 if tokens[0]
not in verbs:
560 if not self._check_spelling(t, words):
562 print(
"misspelled %s in %s" % (t, name))
566 def _static_method(self, module, prefix, name):
567 """For static methods of the form Foo.bar SWIG creates free functions
568 named Foo_bar. Exclude these from spelling checks since the method
569 Foo.bar has already been checked."""
570 if prefix
is None and '_' in name:
571 modobj = eval(module)
572 cls, meth = name.split(
'_', 1)
573 if hasattr(modobj, cls):
574 clsobj = eval(module +
'.' + cls)
575 if hasattr(clsobj, meth):
578 def _check_function_names(self, module, prefix, names, verbs, all,
579 exceptions, words, misspelled):
582 typ = self._get_type(module, name)
583 if name.startswith(
"_")
or name ==
"weakref_proxy":
585 if typ
in (types.BuiltinMethodType, types.MethodType) \
586 or (typ == types.FunctionType
and \
587 not self._static_method(module, prefix, name)):
588 bad.extend(self._check_function_name(prefix, name, verbs, all,
591 if typ == type
and "SwigPyIterator" not in name:
592 members=eval(
"dir("+module+
"."+name+
")")
593 bad.extend(self._check_function_names(module+
"."+name,
594 name, members, verbs, [],
600 """Check that all the functions in the module follow the IMP
601 naming conventions."""
603 verbs=set([
"add",
"remove",
"get",
"set",
"evaluate",
"compute",
"show",
"create",
"destroy",
604 "push",
"pop",
"write",
"read",
"do",
"show",
"load",
"save",
"reset",
606 "clear",
"handle",
"update",
"apply",
"optimize",
"reserve",
"dump",
607 "propose",
"setup",
"teardown",
"visit",
"find",
"run",
"swap",
"link",
610 bad=self._check_function_names(module.__name__,
None, all, verbs, all, exceptions, words, misspelled)
611 message=
"All IMP methods and functions 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 standards_exceptions file. Otherwise, please fix. The current verb list is %(verbs)s" \
612 % {
"bad":
"\n".join(bad),
"verbs":verbs}
613 if len(misspelled) > 0:
614 message +=
"\nMisspelled words: " +
", ".join(set(misspelled)) \
615 +
". Add words to the spelling_exceptions variable " \
616 +
"of the standards_exceptions file if needed."
617 self.assertEqual(len(bad), 0, message)
621 """Check that all the classes in modulename have a show method"""
629 if not eval(
'hasattr(%s.%s, "__swig_destroy__")' \
630 % (modulename.__name__, f)):
632 if self._get_type(modulename.__name__, f) == type \
633 and not f.startswith(
"_") \
634 and not f.endswith(
"_swigregister")\
635 and f
not in exceptions\
636 and not f.endswith(
"Temp")
and not f.endswith(
"Iterator")\
637 and not f.endswith(
"Exception")
and\
638 f
not in modulename._raii_types
and \
639 f
not in modulename._plural_types:
640 if not hasattr(getattr(modulename, f),
'show'):
642 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." \
643 %
"\n".join(not_found)
644 self.assertEqual(len(not_found), 0, message)
646 self.assertIn(e, all,
"Show exception "+e+
" is not a class in module")
647 self.assertTrue(
not hasattr(getattr(modulename, e),
'show'),
648 "Exception "+e+
" is not really a show exception")
651 """Run the named example script.
652 @return a dictionary of all the script's global variables.
653 This can be queried in a test case to make sure
654 the example performed correctly."""
659 path, name = os.path.split(filename)
660 oldsyspath = sys.path[:]
661 olssysargv= sys.argv[:]
662 sys.path.insert(0, path)
667 exec(open(filename).read(), vars)
670 except SystemExit
as e:
671 if e.code != 0
and e.code
is not None:
672 raise _FatalError(
"Example exit with code %s" % str(e.code))
676 sys.path = oldsyspath
679 return _ExecDictProxy(vars)
682 """Run a Python module as if with "python -m <modname>",
683 with the given list of arguments as sys.argv.
685 If module is an already-imported Python module, run its 'main'
686 function and return the result.
688 If module is a string, run the module in a subprocess and return
689 a subprocess.Popen-like object containing the child stdin,
692 def mock_setup_from_argv(*args, **kwargs):
695 if type(module) == type(os):
698 mod = __import__(module, {}, {}, [
''])
699 modpath = mod.__file__
700 if modpath.endswith(
'.pyc'):
701 modpath = modpath[:-1]
702 if type(module) == type(os):
703 old_sys_argv = sys.argv
705 old_setup = IMP.setup_from_argv
706 IMP.setup_from_argv = mock_setup_from_argv
708 sys.argv = [modpath] + args
711 IMP.setup_from_argv = old_setup
712 sys.argv = old_sys_argv
714 return _SubprocessWrapper(sys.executable, [modpath] + args)
717 """Check a Python module designed to be runnable with 'python -m'
718 to make sure it supports standard command line options."""
721 out, err = r.communicate()
722 self.assertEqual(r.returncode, 0)
723 self.assertNotEqual(err,
"")
724 self.assertEqual(out,
"")
727 class _ExecDictProxy(object):
728 """exec returns a Python dictionary, which contains IMP objects, other
729 Python objects, as well as base Python modules (such as sys and
730 __builtins__). If we just delete this dictionary, it is entirely
731 possible that base Python modules are removed from the dictionary
732 *before* some IMP objects. This will prevent the IMP objects' Python
733 destructors from running properly, so C++ objects will not be
734 cleaned up. This class proxies the base dict class, and on deletion
735 attempts to remove keys from the dictionary in an order that allows
736 IMP destructors to fire."""
737 def __init__(self, d):
741 module_type = type(IMP)
744 if type(d[k]) != module_type:
747 for meth
in [
'__contains__',
'__getitem__',
'__iter__',
'__len__',
748 'get',
'has_key',
'items',
'keys',
'values']:
749 exec(
"def %s(self, *args, **keys): "
750 "return self._d.%s(*args, **keys)" % (meth, meth))
753 class _TestResult(unittest.TextTestResult):
755 def __init__(self, stream=None, descriptions=None, verbosity=None):
756 super(_TestResult, self).__init__(stream, descriptions, verbosity)
759 def stopTestRun(self):
760 if 'IMP_TEST_DETAIL_DIR' in os.environ:
761 fname = os.path.join(os.environ[
'IMP_TEST_DETAIL_DIR'],
762 os.path.basename(sys.argv[0]))
763 with open(fname,
'wb')
as fh:
764 pickle.dump(self.all_tests, fh, -1)
765 super(_TestResult, self).stopTestRun()
767 def startTest(self, test):
768 super(_TestResult, self).startTest(test)
769 test.start_time=datetime.datetime.now()
771 def _test_finished(self, test, state, detail=None):
772 delta = datetime.datetime.now() - test.start_time
774 pv= delta.total_seconds()
775 except AttributeError:
776 pv = (float(delta.microseconds) \
777 + (delta.seconds + delta.days * 24 * 3600) * 10**6) / 10**6
779 self.stream.write(
"in %.3fs ... " % pv)
780 if detail
is not None and not isinstance(detail, str):
781 detail = self._exc_info_to_string(detail, test)
782 test_doc = self.getDescription(test)
783 test_name = test.id()
784 if test_name.startswith(
'__main__.'):
785 test_name = test_name[9:]
786 self.all_tests.append({
'name': test_name,
787 'docstring': test_doc,
788 'time': pv,
'state': state,
'detail': detail})
790 def addSuccess(self, test):
791 self._test_finished(test,
'OK')
792 super(_TestResult, self).addSuccess(test)
794 def addError(self, test, err):
795 self._test_finished(test,
'ERROR', err)
796 super(_TestResult, self).addError(test, err)
798 def addFailure(self, test, err):
799 self._test_finished(test,
'FAIL', err)
800 super(_TestResult, self).addFailure(test, err)
802 def addSkip(self, test, reason):
803 self._test_finished(test,
'SKIP', reason)
804 super(_TestResult, self).addSkip(test, reason)
806 def addExpectedFailure(self, test, err):
807 self._test_finished(test,
'EXPFAIL', err)
808 super(_TestResult, self).addExpectedFailure(test, err)
810 def addUnexpectedSuccess(self, test):
811 self._test_finished(test,
'UNEXPSUC')
812 super(_TestResult, self).addUnexpectedSuccess(test)
814 def getDescription(self, test):
815 doc_first_line = test.shortDescription()
816 if self.descriptions
and doc_first_line:
817 return doc_first_line
822 class _TestRunner(unittest.TextTestRunner):
823 def _makeResult(self):
824 return _TestResult(self.stream, self.descriptions, self.verbosity)
828 """Run a set of tests; similar to unittest.main().
829 Obviates the need to separately import the 'unittest' module, and
830 ensures that main() is from the same unittest module that the
831 IMP.test testcases are. In addition, turns on some extra checks
832 (e.g. trying to use deprecated code will cause an exception
836 return unittest.main(testRunner=_TestRunner, *args, **keys)
839 class _SubprocessWrapper(subprocess.Popen):
840 def __init__(self, app, args, cwd=None):
843 if sys.platform ==
'win32' and app != sys.executable:
845 libdir = os.environ[
'PYTHONPATH'].split(
';')[0]
846 env = os.environ.copy()
847 env[
'PATH'] +=
';' + libdir
850 subprocess.Popen.__init__(self, [app]+list(args),
851 stdin=subprocess.PIPE,
852 stdout=subprocess.PIPE,
853 stderr=subprocess.PIPE, env=env, cwd=cwd,
854 universal_newlines=
True)
858 """Super class for simple IMP application test cases"""
859 def _get_application_file_name(self, filename):
862 if sys.platform ==
'win32':
870 """Run an application with the given list of arguments.
871 @return a subprocess.Popen-like object containing the child stdin,
874 filename = self._get_application_file_name(app)
875 if sys.platform ==
'win32':
877 return _SubprocessWrapper(os.path.join(os.environ[
'IMP_BIN_DIR'],
878 filename), args, cwd=cwd)
880 return _SubprocessWrapper(filename, args, cwd=cwd)
883 """Run a Python application with the given list of arguments.
884 The Python application should be self-runnable (i.e. it should
885 be executable and with a #! on the first line).
886 @return a subprocess.Popen-like object containing the child stdin,
890 if sys.executable !=
'/usr/bin/python' and 'IMP_BIN_DIR' in os.environ:
891 return _SubprocessWrapper(sys.executable,
892 [os.path.join(os.environ[
'IMP_BIN_DIR'], app)] + args)
894 return _SubprocessWrapper(app, args)
897 """Import an installed Python application, rather than running it.
898 This is useful to directly test components of the application.
899 @return the Python module object."""
901 import importlib.machinery
905 name = os.path.splitext(app)[0]
906 pathname = os.path.join(os.environ[
'IMP_BIN_DIR'], app)
908 return importlib.machinery.SourceFileLoader(name,
909 pathname).load_module()
911 return imp.load_source(name, pathname)
914 """Run an application with the given list of arguments.
915 @return a subprocess.Popen-like object containing the child stdin,
918 return _SubprocessWrapper(sys.executable, [app]+args)
921 """Assert that the application exited cleanly (return value = 0)."""
923 raise OSError(
"Application exited with signal %d\n" % -ret\
926 self.assertEqual(ret, 0,
927 "Application exited uncleanly, with exit code %d\n" % ret\
931 """Read and return a set of shell commands from a doxygen file.
932 Each command is assumed to be in a \code{.sh}...\endcode block.
933 The doxygen file is specified relative to the test file itself.
934 This is used to make sure the commands shown in an application
935 example actually work (the testcase can also check the resulting
936 files for correctness)."""
937 def win32_normpath(p):
940 return " ".join([os.path.normpath(x)
for x
in p.split()])
941 def fix_win32_command(cmd):
943 if cmd.startswith(
'cp -r '):
944 return 'xcopy /E ' + win32_normpath(cmd[6:])
945 elif cmd.startswith(
'cp '):
946 return 'copy ' + win32_normpath(cmd[3:])
949 d = os.path.dirname(sys.argv[0])
950 doc = os.path.join(d, doxfile)
954 with open(doc)
as fh:
955 for line
in fh.readlines():
956 if '\code{.sh}' in line:
958 elif '\endcode' in line:
961 cmds.append(line.rstrip(
'\r\n').replace(
962 '<imp_example_path>', example_path))
963 if sys.platform ==
'win32':
964 cmds = [fix_win32_command(x)
for x
in cmds]
968 "Print and run a shell command, as returned by read_shell_commands()"
971 p = subprocess.call(cmd, shell=
True)
973 raise OSError(
"%s failed with exit value %d" % (cmd, p))
977 """Check to make sure the number of C++ object references is as expected"""
979 def __init__(self, testcase):
983 IMP._director_objects.cleanup()
984 self.__testcase = testcase
986 self.__basenum = IMP.Object.get_number_of_live_objects()
990 "Make sure that the number of references matches the expected value."
992 IMP._director_objects.cleanup()
995 newnum=IMP.Object.get_number_of_live_objects()-self.__basenum
996 t.assertEqual(newnum, expected,
997 "Number of objects don't match: "\
999 +
" != "+ str(expected) +
" found "+\
1005 """Check to make sure the number of director references is as expected"""
1007 def __init__(self, testcase):
1008 IMP._director_objects.cleanup()
1009 self.__testcase = testcase
1010 self.__basenum = IMP._director_objects.get_object_count()
1013 """Make sure that the number of references matches the expected value.
1014 If force_cleanup is set, clean up any unused references first before
1015 doing the assertion.
1019 IMP._director_objects.cleanup()
1020 t.assertEqual(IMP._director_objects.get_object_count() \
1021 - self.__basenum, expected)
1029 if sys.platform ==
'win32' and 'PYTHONPATH' in os.environ \
1030 and 'IMP_BIN_DIR' in os.environ:
1031 libdir = os.environ[
'PYTHONPATH'].split(
';')[0]
1032 bindir = os.environ[
'IMP_BIN_DIR']
1033 path = os.environ[
'PATH']
1034 if libdir
not in path
or bindir
not in path:
1035 os.environ[
'PATH'] = bindir +
';' + libdir +
';' + path
1039 '''Return the version of this module, as a string'''
1043 '''Return the fully-qualified name of this module'''
1047 '''Return the full path to one of this module's data files'''
1049 return IMP._get_module_data_path(
"test", fname)
1052 '''Return the full path to one of this module's example files'''
1054 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.