LSST Applications  21.0.0+04719a4bac,21.0.0-1-ga51b5d4+f5e6047307,21.0.0-11-g2b59f77+a9c1acf22d,21.0.0-11-ga42c5b2+86977b0b17,21.0.0-12-gf4ce030+76814010d2,21.0.0-13-g1721dae+760e7a6536,21.0.0-13-g3a573fe+768d78a30a,21.0.0-15-g5a7caf0+f21cbc5713,21.0.0-16-g0fb55c1+b60e2d390c,21.0.0-19-g4cded4ca+71a93a33c0,21.0.0-2-g103fe59+bb20972958,21.0.0-2-g45278ab+04719a4bac,21.0.0-2-g5242d73+3ad5d60fb1,21.0.0-2-g7f82c8f+8babb168e8,21.0.0-2-g8f08a60+06509c8b61,21.0.0-2-g8faa9b5+616205b9df,21.0.0-2-ga326454+8babb168e8,21.0.0-2-gde069b7+5e4aea9c2f,21.0.0-2-gecfae73+1d3a86e577,21.0.0-2-gfc62afb+3ad5d60fb1,21.0.0-25-g1d57be3cd+e73869a214,21.0.0-3-g357aad2+ed88757d29,21.0.0-3-g4a4ce7f+3ad5d60fb1,21.0.0-3-g4be5c26+3ad5d60fb1,21.0.0-3-g65f322c+e0b24896a3,21.0.0-3-g7d9da8d+616205b9df,21.0.0-3-ge02ed75+a9c1acf22d,21.0.0-4-g591bb35+a9c1acf22d,21.0.0-4-g65b4814+b60e2d390c,21.0.0-4-gccdca77+0de219a2bc,21.0.0-4-ge8a399c+6c55c39e83,21.0.0-5-gd00fb1e+05fce91b99,21.0.0-6-gc675373+3ad5d60fb1,21.0.0-64-g1122c245+4fb2b8f86e,21.0.0-7-g04766d7+cd19d05db2,21.0.0-7-gdf92d54+04719a4bac,21.0.0-8-g5674e7b+d1bd76f71f,master-gac4afde19b+a9c1acf22d,w.2021.13
LSST Data Management Base Package
Classes | Functions | Variables
lsst.utils.tests Namespace Reference

Classes

class  MemoryTestCase
 
class  ExecutablesTestCase
 
class  TestCase
 

Functions

def init ()
 
def sort_tests (tests)
 
def suiteClassWrapper (tests)
 
def getTempFilePath (ext, expectOutput=True)
 
def inTestCase (func)
 
def debugger (*exceptions)
 
def plotImageDiff (lhs, rhs, bad=None, diff=None, plotFileName=None)
 
def assertFloatsAlmostEqual (testCase, lhs, rhs, rtol=sys.float_info.epsilon, atol=sys.float_info.epsilon, relTo=None, printFailures=True, plotOnFailure=False, plotFileName=None, invert=False, msg=None)
 
def assertFloatsNotEqual (testCase, lhs, rhs, **kwds)
 
def assertFloatsEqual (testCase, lhs, rhs, **kwargs)
 
def classParameters (**settings)
 
def methodParameters (**settings)
 
def temporaryDirectory ()
 

Variables

 open_files = set()
 

Function Documentation

◆ assertFloatsAlmostEqual()

def lsst.utils.tests.assertFloatsAlmostEqual (   testCase,
  lhs,
  rhs,
  rtol = sys.float_info.epsilon,
  atol = sys.float_info.epsilon,
  relTo = None,
  printFailures = True,
  plotOnFailure = False,
  plotFileName = None,
  invert = False,
  msg = None 
)
Highly-configurable floating point comparisons for scalars and arrays.

The test assertion will fail if all elements ``lhs`` and ``rhs`` are not
equal to within the tolerances specified by ``rtol`` and ``atol``.
More precisely, the comparison is:

``abs(lhs - rhs) <= relTo*rtol OR abs(lhs - rhs) <= atol``

If ``rtol`` or ``atol`` is `None`, that term in the comparison is not
performed at all.

When not specified, ``relTo`` is the elementwise maximum of the absolute
values of ``lhs`` and ``rhs``.  If set manually, it should usually be set
to either ``lhs`` or ``rhs``, or a scalar value typical of what is
expected.

Parameters
----------
testCase : `unittest.TestCase`
    Instance the test is part of.
lhs : scalar or array-like
    LHS value(s) to compare; may be a scalar or array-like of any
    dimension.
rhs : scalar or array-like
    RHS value(s) to compare; may be a scalar or array-like of any
    dimension.
rtol : `float`, optional
    Relative tolerance for comparison; defaults to double-precision
    epsilon.
atol : `float`, optional
    Absolute tolerance for comparison; defaults to double-precision
    epsilon.
relTo : `float`, optional
    Value to which comparison with rtol is relative.
printFailures : `bool`, optional
    Upon failure, print all inequal elements as part of the message.
plotOnFailure : `bool`, optional
    Upon failure, plot the originals and their residual with matplotlib.
    Only 2-d arrays are supported.
plotFileName : `str`, optional
    Filename to save the plot to.  If `None`, the plot will be displayed in
    a window.
invert : `bool`, optional
    If `True`, invert the comparison and fail only if any elements *are*
    equal. Used to implement `~lsst.utils.tests.assertFloatsNotEqual`,
    which should generally be used instead for clarity.
msg : `str`, optional
    String to append to the error message when assert fails.

Raises
------
AssertionError
    The values are not almost equal.

Definition at line 522 of file tests.py.

525  plotFileName=None, invert=False, msg=None):
526  """Highly-configurable floating point comparisons for scalars and arrays.
527 
528  The test assertion will fail if all elements ``lhs`` and ``rhs`` are not
529  equal to within the tolerances specified by ``rtol`` and ``atol``.
530  More precisely, the comparison is:
531 
532  ``abs(lhs - rhs) <= relTo*rtol OR abs(lhs - rhs) <= atol``
533 
534  If ``rtol`` or ``atol`` is `None`, that term in the comparison is not
535  performed at all.
536 
537  When not specified, ``relTo`` is the elementwise maximum of the absolute
538  values of ``lhs`` and ``rhs``. If set manually, it should usually be set
539  to either ``lhs`` or ``rhs``, or a scalar value typical of what is
540  expected.
541 
542  Parameters
543  ----------
544  testCase : `unittest.TestCase`
545  Instance the test is part of.
546  lhs : scalar or array-like
547  LHS value(s) to compare; may be a scalar or array-like of any
548  dimension.
549  rhs : scalar or array-like
550  RHS value(s) to compare; may be a scalar or array-like of any
551  dimension.
552  rtol : `float`, optional
553  Relative tolerance for comparison; defaults to double-precision
554  epsilon.
555  atol : `float`, optional
556  Absolute tolerance for comparison; defaults to double-precision
557  epsilon.
558  relTo : `float`, optional
559  Value to which comparison with rtol is relative.
560  printFailures : `bool`, optional
561  Upon failure, print all inequal elements as part of the message.
562  plotOnFailure : `bool`, optional
563  Upon failure, plot the originals and their residual with matplotlib.
564  Only 2-d arrays are supported.
565  plotFileName : `str`, optional
566  Filename to save the plot to. If `None`, the plot will be displayed in
567  a window.
568  invert : `bool`, optional
569  If `True`, invert the comparison and fail only if any elements *are*
570  equal. Used to implement `~lsst.utils.tests.assertFloatsNotEqual`,
571  which should generally be used instead for clarity.
572  msg : `str`, optional
573  String to append to the error message when assert fails.
574 
575  Raises
576  ------
577  AssertionError
578  The values are not almost equal.
579  """
580  if not numpy.isfinite(lhs).all():
581  testCase.fail("Non-finite values in lhs")
582  if not numpy.isfinite(rhs).all():
583  testCase.fail("Non-finite values in rhs")
584  diff = lhs - rhs
585  absDiff = numpy.abs(lhs - rhs)
586  if rtol is not None:
587  if relTo is None:
588  relTo = numpy.maximum(numpy.abs(lhs), numpy.abs(rhs))
589  else:
590  relTo = numpy.abs(relTo)
591  bad = absDiff > rtol*relTo
592  if atol is not None:
593  bad = numpy.logical_and(bad, absDiff > atol)
594  else:
595  if atol is None:
596  raise ValueError("rtol and atol cannot both be None")
597  bad = absDiff > atol
598  failed = numpy.any(bad)
599  if invert:
600  failed = not failed
601  bad = numpy.logical_not(bad)
602  cmpStr = "=="
603  failStr = "are the same"
604  else:
605  cmpStr = "!="
606  failStr = "differ"
607  errMsg = []
608  if failed:
609  if numpy.isscalar(bad):
610  if rtol is None:
611  errMsg = ["%s %s %s; diff=%s with atol=%s"
612  % (lhs, cmpStr, rhs, absDiff, atol)]
613  elif atol is None:
614  errMsg = ["%s %s %s; diff=%s/%s=%s with rtol=%s"
615  % (lhs, cmpStr, rhs, absDiff, relTo, absDiff/relTo, rtol)]
616  else:
617  errMsg = ["%s %s %s; diff=%s/%s=%s with rtol=%s, atol=%s"
618  % (lhs, cmpStr, rhs, absDiff, relTo, absDiff/relTo, rtol, atol)]
619  else:
620  errMsg = ["%d/%d elements %s with rtol=%s, atol=%s"
621  % (bad.sum(), bad.size, failStr, rtol, atol)]
622  if plotOnFailure:
623  if len(lhs.shape) != 2 or len(rhs.shape) != 2:
624  raise ValueError("plotOnFailure is only valid for 2-d arrays")
625  try:
626  plotImageDiff(lhs, rhs, bad, diff=diff, plotFileName=plotFileName)
627  except ImportError:
628  errMsg.append("Failure plot requested but matplotlib could not be imported.")
629  if printFailures:
630  # Make sure everything is an array if any of them are, so we can treat
631  # them the same (diff and absDiff are arrays if either rhs or lhs is),
632  # and we don't get here if neither is.
633  if numpy.isscalar(relTo):
634  relTo = numpy.ones(bad.shape, dtype=float) * relTo
635  if numpy.isscalar(lhs):
636  lhs = numpy.ones(bad.shape, dtype=float) * lhs
637  if numpy.isscalar(rhs):
638  rhs = numpy.ones(bad.shape, dtype=float) * rhs
639  if rtol is None:
640  for a, b, diff in zip(lhs[bad], rhs[bad], absDiff[bad]):
641  errMsg.append("%s %s %s (diff=%s)" % (a, cmpStr, b, diff))
642  else:
643  for a, b, diff, rel in zip(lhs[bad], rhs[bad], absDiff[bad], relTo[bad]):
644  errMsg.append("%s %s %s (diff=%s/%s=%s)" % (a, cmpStr, b, diff, rel, diff/rel))
645 
646  if msg is not None:
647  errMsg.append(msg)
648  testCase.assertFalse(failed, msg="\n".join(errMsg))
649 
650 
651 @inTestCase
bool all(CoordinateExpr< N > const &expr) noexcept
Return true if all elements are true.
def plotImageDiff(lhs, rhs, bad=None, diff=None, plotFileName=None)
Definition: tests.py:457

◆ assertFloatsEqual()

def lsst.utils.tests.assertFloatsEqual (   testCase,
  lhs,
  rhs,
**  kwargs 
)
Assert that lhs == rhs (both numeric types, whether scalar or array).

See `~lsst.utils.tests.assertFloatsAlmostEqual` (called with
``rtol=atol=0``) for more information.

Parameters
----------
testCase : `unittest.TestCase`
    Instance the test is part of.
lhs : scalar or array-like
    LHS value(s) to compare; may be a scalar or array-like of any
    dimension.
rhs : scalar or array-like
    RHS value(s) to compare; may be a scalar or array-like of any
    dimension.

Raises
------
AssertionError
    The values are not equal.

Definition at line 679 of file tests.py.

679 def assertFloatsEqual(testCase, lhs, rhs, **kwargs):
680  """
681  Assert that lhs == rhs (both numeric types, whether scalar or array).
682 
683  See `~lsst.utils.tests.assertFloatsAlmostEqual` (called with
684  ``rtol=atol=0``) for more information.
685 
686  Parameters
687  ----------
688  testCase : `unittest.TestCase`
689  Instance the test is part of.
690  lhs : scalar or array-like
691  LHS value(s) to compare; may be a scalar or array-like of any
692  dimension.
693  rhs : scalar or array-like
694  RHS value(s) to compare; may be a scalar or array-like of any
695  dimension.
696 
697  Raises
698  ------
699  AssertionError
700  The values are not equal.
701  """
702  return assertFloatsAlmostEqual(testCase, lhs, rhs, rtol=0, atol=0, **kwargs)
703 
704 
def assertFloatsEqual(testCase, lhs, rhs, **kwargs)
Definition: tests.py:679
def assertFloatsAlmostEqual(testCase, lhs, rhs, rtol=sys.float_info.epsilon, atol=sys.float_info.epsilon, relTo=None, printFailures=True, plotOnFailure=False, plotFileName=None, invert=False, msg=None)
Definition: tests.py:525

◆ assertFloatsNotEqual()

def lsst.utils.tests.assertFloatsNotEqual (   testCase,
  lhs,
  rhs,
**  kwds 
)
Fail a test if the given floating point values are equal to within the
given tolerances.

See `~lsst.utils.tests.assertFloatsAlmostEqual` (called with
``rtol=atol=0``) for more information.

Parameters
----------
testCase : `unittest.TestCase`
    Instance the test is part of.
lhs : scalar or array-like
    LHS value(s) to compare; may be a scalar or array-like of any
    dimension.
rhs : scalar or array-like
    RHS value(s) to compare; may be a scalar or array-like of any
    dimension.

Raises
------
AssertionError
    The values are almost equal.

Definition at line 652 of file tests.py.

652 def assertFloatsNotEqual(testCase, lhs, rhs, **kwds):
653  """Fail a test if the given floating point values are equal to within the
654  given tolerances.
655 
656  See `~lsst.utils.tests.assertFloatsAlmostEqual` (called with
657  ``rtol=atol=0``) for more information.
658 
659  Parameters
660  ----------
661  testCase : `unittest.TestCase`
662  Instance the test is part of.
663  lhs : scalar or array-like
664  LHS value(s) to compare; may be a scalar or array-like of any
665  dimension.
666  rhs : scalar or array-like
667  RHS value(s) to compare; may be a scalar or array-like of any
668  dimension.
669 
670  Raises
671  ------
672  AssertionError
673  The values are almost equal.
674  """
675  return assertFloatsAlmostEqual(testCase, lhs, rhs, invert=True, **kwds)
676 
677 
678 @inTestCase
def assertFloatsNotEqual(testCase, lhs, rhs, **kwds)
Definition: tests.py:652

◆ classParameters()

def lsst.utils.tests.classParameters ( **  settings)
Class decorator for generating unit tests

This decorator generates classes with class variables according to the
supplied ``settings``.

Parameters
----------
**settings : `dict` (`str`: iterable)
    The lists of test parameters to set as class variables in turn. Each
    should be an iterable of the same length.

Examples
--------
::

    @classParameters(foo=[1, 2], bar=[3, 4])
    class MyTestCase(unittest.TestCase):
        ...

will generate two classes, as if you wrote::

    class MyTestCase_1_3(unittest.TestCase):
        foo = 1
        bar = 3
        ...

    class MyTestCase_2_4(unittest.TestCase):
        foo = 2
        bar = 4
        ...

Note that the values are embedded in the class name.

Definition at line 737 of file tests.py.

737 def classParameters(**settings):
738  """Class decorator for generating unit tests
739 
740  This decorator generates classes with class variables according to the
741  supplied ``settings``.
742 
743  Parameters
744  ----------
745  **settings : `dict` (`str`: iterable)
746  The lists of test parameters to set as class variables in turn. Each
747  should be an iterable of the same length.
748 
749  Examples
750  --------
751  ::
752 
753  @classParameters(foo=[1, 2], bar=[3, 4])
754  class MyTestCase(unittest.TestCase):
755  ...
756 
757  will generate two classes, as if you wrote::
758 
759  class MyTestCase_1_3(unittest.TestCase):
760  foo = 1
761  bar = 3
762  ...
763 
764  class MyTestCase_2_4(unittest.TestCase):
765  foo = 2
766  bar = 4
767  ...
768 
769  Note that the values are embedded in the class name.
770  """
771  def decorator(cls):
772  module = sys.modules[cls.__module__].__dict__
773  for params in _settingsIterator(settings):
774  name = f"{cls.__name__}_{'_'.join(str(vv) for vv in params.values())}"
775  bindings = dict(cls.__dict__)
776  bindings.update(params)
777  module[name] = type(name, (cls,), bindings)
778  return decorator
779 
780 
table::Key< int > type
Definition: Detector.cc:163
def classParameters(**settings)
Definition: tests.py:737

◆ debugger()

def lsst.utils.tests.debugger ( exceptions)
Decorator to enter the debugger when there's an uncaught exception

To use, just slap a ``@debugger()`` on your function.

You may provide specific exception classes to catch as arguments to
the decorator function, e.g.,
``@debugger(RuntimeError, NotImplementedError)``.
This defaults to just `AssertionError`, for use on `unittest.TestCase`
methods.

Code provided by "Rosh Oxymoron" on StackOverflow:
http://stackoverflow.com/questions/4398967/python-unit-testing-automatically-running-the-debugger-when-a-test-fails

Notes
-----
Consider using ``pytest --pdb`` instead of this decorator.

Definition at line 423 of file tests.py.

423 def debugger(*exceptions):
424  """Decorator to enter the debugger when there's an uncaught exception
425 
426  To use, just slap a ``@debugger()`` on your function.
427 
428  You may provide specific exception classes to catch as arguments to
429  the decorator function, e.g.,
430  ``@debugger(RuntimeError, NotImplementedError)``.
431  This defaults to just `AssertionError`, for use on `unittest.TestCase`
432  methods.
433 
434  Code provided by "Rosh Oxymoron" on StackOverflow:
435  http://stackoverflow.com/questions/4398967/python-unit-testing-automatically-running-the-debugger-when-a-test-fails
436 
437  Notes
438  -----
439  Consider using ``pytest --pdb`` instead of this decorator.
440  """
441  if not exceptions:
442  exceptions = (Exception, )
443 
444  def decorator(f):
445  @functools.wraps(f)
446  def wrapper(*args, **kwargs):
447  try:
448  return f(*args, **kwargs)
449  except exceptions:
450  import sys
451  import pdb
452  pdb.post_mortem(sys.exc_info()[2])
453  return wrapper
454  return decorator
455 
456 
def debugger(*exceptions)
Definition: tests.py:423

◆ getTempFilePath()

def lsst.utils.tests.getTempFilePath (   ext,
  expectOutput = True 
)
Return a path suitable for a temporary file and try to delete the
file on success

If the with block completes successfully then the file is deleted,
if possible; failure results in a printed warning.
If a file is remains when it should not, a RuntimeError exception is
raised. This exception is also raised if a file is not present on context
manager exit when one is expected to exist.
If the block exits with an exception the file if left on disk so it can be
examined. The file name has a random component such that nested context
managers can be used with the same file suffix.

Parameters
----------

ext : `str`
    File name extension, e.g. ``.fits``.
expectOutput : `bool`, optional
    If `True`, a file should be created within the context manager.
    If `False`, a file should not be present when the context manager
    exits.

Returns
-------
`str`
    Path for a temporary file. The path is a combination of the caller's
    file path and the name of the top-level function

Notes
-----
::

    # file tests/testFoo.py
    import unittest
    import lsst.utils.tests
    class FooTestCase(unittest.TestCase):
        def testBasics(self):
            self.runTest()

        def runTest(self):
            with lsst.utils.tests.getTempFilePath(".fits") as tmpFile:
                # if tests/.tests exists then
                # tmpFile = "tests/.tests/testFoo_testBasics.fits"
                # otherwise tmpFile = "testFoo_testBasics.fits"
                ...
                # at the end of this "with" block the path tmpFile will be
                # deleted, but only if the file exists and the "with"
                # block terminated normally (rather than with an exception)
    ...

Definition at line 310 of file tests.py.

310 def getTempFilePath(ext, expectOutput=True):
311  """Return a path suitable for a temporary file and try to delete the
312  file on success
313 
314  If the with block completes successfully then the file is deleted,
315  if possible; failure results in a printed warning.
316  If a file is remains when it should not, a RuntimeError exception is
317  raised. This exception is also raised if a file is not present on context
318  manager exit when one is expected to exist.
319  If the block exits with an exception the file if left on disk so it can be
320  examined. The file name has a random component such that nested context
321  managers can be used with the same file suffix.
322 
323  Parameters
324  ----------
325 
326  ext : `str`
327  File name extension, e.g. ``.fits``.
328  expectOutput : `bool`, optional
329  If `True`, a file should be created within the context manager.
330  If `False`, a file should not be present when the context manager
331  exits.
332 
333  Returns
334  -------
335  `str`
336  Path for a temporary file. The path is a combination of the caller's
337  file path and the name of the top-level function
338 
339  Notes
340  -----
341  ::
342 
343  # file tests/testFoo.py
344  import unittest
345  import lsst.utils.tests
346  class FooTestCase(unittest.TestCase):
347  def testBasics(self):
348  self.runTest()
349 
350  def runTest(self):
351  with lsst.utils.tests.getTempFilePath(".fits") as tmpFile:
352  # if tests/.tests exists then
353  # tmpFile = "tests/.tests/testFoo_testBasics.fits"
354  # otherwise tmpFile = "testFoo_testBasics.fits"
355  ...
356  # at the end of this "with" block the path tmpFile will be
357  # deleted, but only if the file exists and the "with"
358  # block terminated normally (rather than with an exception)
359  ...
360  """
361  stack = inspect.stack()
362  # get name of first function in the file
363  for i in range(2, len(stack)):
364  frameInfo = inspect.getframeinfo(stack[i][0])
365  if i == 2:
366  callerFilePath = frameInfo.filename
367  callerFuncName = frameInfo.function
368  elif callerFilePath == frameInfo.filename:
369  # this function called the previous function
370  callerFuncName = frameInfo.function
371  else:
372  break
373 
374  callerDir, callerFileNameWithExt = os.path.split(callerFilePath)
375  callerFileName = os.path.splitext(callerFileNameWithExt)[0]
376  outDir = os.path.join(callerDir, ".tests")
377  if not os.path.isdir(outDir):
378  outDir = ""
379  prefix = "%s_%s-" % (callerFileName, callerFuncName)
380  outPath = tempfile.mktemp(dir=outDir, suffix=ext, prefix=prefix)
381  if os.path.exists(outPath):
382  # There should not be a file there given the randomizer. Warn and remove.
383  # Use stacklevel 3 so that the warning is reported from the end of the with block
384  warnings.warn("Unexpectedly found pre-existing tempfile named %r" % (outPath,),
385  stacklevel=3)
386  try:
387  os.remove(outPath)
388  except OSError:
389  pass
390 
391  yield outPath
392 
393  fileExists = os.path.exists(outPath)
394  if expectOutput:
395  if not fileExists:
396  raise RuntimeError("Temp file expected named {} but none found".format(outPath))
397  else:
398  if fileExists:
399  raise RuntimeError("Unexpectedly discovered temp file named {}".format(outPath))
400  # Try to clean up the file regardless
401  if fileExists:
402  try:
403  os.remove(outPath)
404  except OSError as e:
405  # Use stacklevel 3 so that the warning is reported from the end of the with block
406  warnings.warn("Warning: could not remove file %r: %s" % (outPath, e), stacklevel=3)
407 
408 
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)
Definition: history.py:174
def getTempFilePath(ext, expectOutput=True)
Definition: tests.py:310

◆ init()

def lsst.utils.tests.init ( )
Initialize the memory tester and file descriptor leak tester.

Definition at line 59 of file tests.py.

59 def init():
60  """Initialize the memory tester and file descriptor leak tester."""
61  global open_files
62  # Reset the list of open files
63  open_files = _get_open_files()
64 
65 
def init()
Definition: tests.py:59

◆ inTestCase()

def lsst.utils.tests.inTestCase (   func)
A decorator to add a free function to our custom TestCase class, while also
making it available as a free function.

Definition at line 415 of file tests.py.

415 def inTestCase(func):
416  """A decorator to add a free function to our custom TestCase class, while also
417  making it available as a free function.
418  """
419  setattr(TestCase, func.__name__, func)
420  return func
421 
422 
def inTestCase(func)
Definition: tests.py:415

◆ methodParameters()

def lsst.utils.tests.methodParameters ( **  settings)
Method decorator for unit tests

This decorator iterates over the supplied settings, using
``TestCase.subTest`` to communicate the values in the event of a failure.

Parameters
----------
**settings : `dict` (`str`: iterable)
    The lists of test parameters. Each should be an iterable of the same
    length.

Examples
--------
::

    @methodParameters(foo=[1, 2], bar=[3, 4])
    def testSomething(self, foo, bar):
        ...

will run::

    testSomething(foo=1, bar=3)
    testSomething(foo=2, bar=4)

Definition at line 781 of file tests.py.

781 def methodParameters(**settings):
782  """Method decorator for unit tests
783 
784  This decorator iterates over the supplied settings, using
785  ``TestCase.subTest`` to communicate the values in the event of a failure.
786 
787  Parameters
788  ----------
789  **settings : `dict` (`str`: iterable)
790  The lists of test parameters. Each should be an iterable of the same
791  length.
792 
793  Examples
794  --------
795  ::
796 
797  @methodParameters(foo=[1, 2], bar=[3, 4])
798  def testSomething(self, foo, bar):
799  ...
800 
801  will run::
802 
803  testSomething(foo=1, bar=3)
804  testSomething(foo=2, bar=4)
805  """
806  def decorator(func):
807  @functools.wraps(func)
808  def wrapper(self, *args, **kwargs):
809  for params in _settingsIterator(settings):
810  kwargs.update(params)
811  with self.subTest(**params):
812  func(self, *args, **kwargs)
813  return wrapper
814  return decorator
815 
816 
817 @contextlib.contextmanager
def methodParameters(**settings)
Definition: tests.py:781

◆ plotImageDiff()

def lsst.utils.tests.plotImageDiff (   lhs,
  rhs,
  bad = None,
  diff = None,
  plotFileName = None 
)
Plot the comparison of two 2-d NumPy arrays.

Parameters
----------
lhs : `numpy.ndarray`
    LHS values to compare; a 2-d NumPy array
rhs : `numpy.ndarray`
    RHS values to compare; a 2-d NumPy array
bad : `numpy.ndarray`
    A 2-d boolean NumPy array of values to emphasize in the plots
diff : `numpy.ndarray`
    difference array; a 2-d NumPy array, or None to show lhs-rhs
plotFileName : `str`
    Filename to save the plot to.  If None, the plot will be displayed in
    a window.

Notes
-----
This method uses `matplotlib` and imports it internally; it should be
wrapped in a try/except block within packages that do not depend on
`matplotlib` (including `~lsst.utils`).

Definition at line 457 of file tests.py.

457 def plotImageDiff(lhs, rhs, bad=None, diff=None, plotFileName=None):
458  """Plot the comparison of two 2-d NumPy arrays.
459 
460  Parameters
461  ----------
462  lhs : `numpy.ndarray`
463  LHS values to compare; a 2-d NumPy array
464  rhs : `numpy.ndarray`
465  RHS values to compare; a 2-d NumPy array
466  bad : `numpy.ndarray`
467  A 2-d boolean NumPy array of values to emphasize in the plots
468  diff : `numpy.ndarray`
469  difference array; a 2-d NumPy array, or None to show lhs-rhs
470  plotFileName : `str`
471  Filename to save the plot to. If None, the plot will be displayed in
472  a window.
473 
474  Notes
475  -----
476  This method uses `matplotlib` and imports it internally; it should be
477  wrapped in a try/except block within packages that do not depend on
478  `matplotlib` (including `~lsst.utils`).
479  """
480  from matplotlib import pyplot
481  if diff is None:
482  diff = lhs - rhs
483  pyplot.figure()
484  if bad is not None:
485  # make an rgba image that's red and transparent where not bad
486  badImage = numpy.zeros(bad.shape + (4,), dtype=numpy.uint8)
487  badImage[:, :, 0] = 255
488  badImage[:, :, 1] = 0
489  badImage[:, :, 2] = 0
490  badImage[:, :, 3] = 255*bad
491  vmin1 = numpy.minimum(numpy.min(lhs), numpy.min(rhs))
492  vmax1 = numpy.maximum(numpy.max(lhs), numpy.max(rhs))
493  vmin2 = numpy.min(diff)
494  vmax2 = numpy.max(diff)
495  for n, (image, title) in enumerate([(lhs, "lhs"), (rhs, "rhs"), (diff, "diff")]):
496  pyplot.subplot(2, 3, n + 1)
497  im1 = pyplot.imshow(image, cmap=pyplot.cm.gray, interpolation='nearest', origin='lower',
498  vmin=vmin1, vmax=vmax1)
499  if bad is not None:
500  pyplot.imshow(badImage, alpha=0.2, interpolation='nearest', origin='lower')
501  pyplot.axis("off")
502  pyplot.title(title)
503  pyplot.subplot(2, 3, n + 4)
504  im2 = pyplot.imshow(image, cmap=pyplot.cm.gray, interpolation='nearest', origin='lower',
505  vmin=vmin2, vmax=vmax2)
506  if bad is not None:
507  pyplot.imshow(badImage, alpha=0.2, interpolation='nearest', origin='lower')
508  pyplot.axis("off")
509  pyplot.title(title)
510  pyplot.subplots_adjust(left=0.05, bottom=0.05, top=0.92, right=0.75, wspace=0.05, hspace=0.05)
511  cax1 = pyplot.axes([0.8, 0.55, 0.05, 0.4])
512  pyplot.colorbar(im1, cax=cax1)
513  cax2 = pyplot.axes([0.8, 0.05, 0.05, 0.4])
514  pyplot.colorbar(im2, cax=cax2)
515  if plotFileName:
516  pyplot.savefig(plotFileName)
517  else:
518  pyplot.show()
519 
520 
521 @inTestCase

◆ sort_tests()

def lsst.utils.tests.sort_tests (   tests)
Sort supplied test suites such that MemoryTestCases are at the end.

`lsst.utils.tests.MemoryTestCase` tests should always run after any other
tests in the module.

Parameters
----------
tests : sequence
    Sequence of test suites.

Returns
-------
suite : `unittest.TestSuite`
    A combined `~unittest.TestSuite` with
    `~lsst.utils.tests.MemoryTestCase` at the end.

Definition at line 66 of file tests.py.

66 def sort_tests(tests):
67  """Sort supplied test suites such that MemoryTestCases are at the end.
68 
69  `lsst.utils.tests.MemoryTestCase` tests should always run after any other
70  tests in the module.
71 
72  Parameters
73  ----------
74  tests : sequence
75  Sequence of test suites.
76 
77  Returns
78  -------
79  suite : `unittest.TestSuite`
80  A combined `~unittest.TestSuite` with
81  `~lsst.utils.tests.MemoryTestCase` at the end.
82  """
83 
84  suite = unittest.TestSuite()
85  memtests = []
86  for test_suite in tests:
87  try:
88  # Just test the first test method in the suite for MemoryTestCase
89  # Use loop rather than next as it is possible for a test class
90  # to not have any test methods and the Python community prefers
91  # for loops over catching a StopIteration exception.
92  bases = None
93  for method in test_suite:
94  bases = inspect.getmro(method.__class__)
95  break
96  if bases is not None and MemoryTestCase in bases:
97  memtests.append(test_suite)
98  else:
99  suite.addTests(test_suite)
100  except TypeError:
101  if isinstance(test_suite, MemoryTestCase):
102  memtests.append(test_suite)
103  else:
104  suite.addTest(test_suite)
105  suite.addTests(memtests)
106  return suite
107 
108 
def sort_tests(tests)
Definition: tests.py:66

◆ suiteClassWrapper()

def lsst.utils.tests.suiteClassWrapper (   tests)

Definition at line 109 of file tests.py.

109 def suiteClassWrapper(tests):
110  return unittest.TestSuite(sort_tests(tests))
111 
112 
113 # Replace the suiteClass callable in the defaultTestLoader
114 # so that we can reorder the test ordering. This will have
115 # no effect if no memory test cases are found.
116 unittest.defaultTestLoader.suiteClass = suiteClassWrapper
117 
118 
def suiteClassWrapper(tests)
Definition: tests.py:109

◆ temporaryDirectory()

def lsst.utils.tests.temporaryDirectory ( )
Context manager that creates and destroys a temporary directory.

The difference from `tempfile.TemporaryDirectory` is that this ignores
errors when deleting a directory, which may happen with some filesystems.

Definition at line 818 of file tests.py.

818 def temporaryDirectory():
819  """Context manager that creates and destroys a temporary directory.
820 
821  The difference from `tempfile.TemporaryDirectory` is that this ignores
822  errors when deleting a directory, which may happen with some filesystems.
823  """
824  tmpdir = tempfile.mkdtemp()
825  yield tmpdir
826  shutil.rmtree(tmpdir, ignore_errors=True)
def temporaryDirectory()
Definition: tests.py:818

Variable Documentation

◆ open_files

lsst.utils.tests.open_files = set()

Definition at line 44 of file tests.py.