Coverage for tests/test_argumentParser.py : 18%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
# # LSST Data Management System # Copyright 2008-2015 AURA/LSST. # # This product includes software developed by the # LSST Project (http://www.lsst.org/). # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the LSST License Statement and # the GNU General Public License along with this program. If not, # see <https://www.lsstcorp.org/LegalNotices/>. #
def capture(): """Context manager to intercept stdout/err
Use as: with capture() as out: print 'hi'
http://stackoverflow.com/questions/5136611/capture-stdout-from-a-script-in-python """ import sys from io import StringIO oldout, olderr = sys.stdout, sys.stderr try: out = [StringIO(), StringIO()] sys.stdout, sys.stderr = out yield out finally: sys.stdout, sys.stderr = oldout, olderr out[0] = out[0].getvalue() out[1] = out[1].getvalue()
dtype=str, default="multiLineDoc") optional=True)
"""A test case for ArgumentParser."""
self.ap = pipeBase.InputOnlyArgumentParser(name="argumentParser") self.ap.add_id_argument("--id", "raw", "help text") self.ap.add_id_argument("--otherId", "raw", "more help") self.config = SampleConfig() os.environ.pop("PIPE_INPUT_ROOT", None) os.environ.pop("PIPE_CALIB_ROOT", None) os.environ.pop("PIPE_OUTPUT_ROOT", None)
del self.ap del self.config
"""Test --id basics""" namespace = self.ap.parse_args( config=self.config, args=[DataPath, "--id", "visit=1", "filter=g"], ) self.assertEqual(len(namespace.id.idList), 1) self.assertEqual(len(namespace.id.refList), 1)
namespace = self.ap.parse_args( config=self.config, args=[DataPath, "--id", "visit=22", "filter=g"], ) self.assertEqual(len(namespace.id.idList), 1) self.assertEqual(len(namespace.id.refList), 0) # no data for this ID
"""Test --other""" # By itself namespace = self.ap.parse_args( config=self.config, args=[DataPath, "--other", "visit=99"], ) self.assertEqual(len(namespace.otherId.idList), 1) self.assertEqual(len(namespace.otherId.refList), 0)
# And together namespace = self.ap.parse_args( config=self.config, args=[DataPath, "--id", "visit=1", "--other", "visit=99"], ) self.assertEqual(len(namespace.id.idList), 1) self.assertEqual(len(namespace.id.refList), 1) self.assertEqual(len(namespace.otherId.idList), 1) self.assertEqual(len(namespace.otherId.refList), 0) # no data for this ID
"""Test --id cross product, including order""" visitList = (1, 2, 3) filterList = ("g", "r") namespace = self.ap.parse_args( config=self.config, args=[ DataPath, "--id", "filter=%s" % ("^".join(filterList),), "visit=%s" % ("^".join(str(visit) for visit in visitList),), ] ) self.assertEqual(len(namespace.id.idList), 6) predValList = itertools.product(filterList, visitList) for id, predVal in zip(namespace.id.idList, predValList): idVal = tuple(id[key] for key in ("filter", "visit")) self.assertEqual(idVal, predVal) self.assertEqual(len(namespace.id.refList), 3) # only have data for three of these
"""Verify that each ID name can only appear once in a given ID argument""" with self.assertRaises(SystemExit): self.ap.parse_args(config=self.config, args=[DataPath, "--id", "visit=1", "visit=2"], )
"""Test --config""" namespace = self.ap.parse_args( config=self.config, args=[DataPath, "--config", "boolItem=False", "floatItem=-67.1", "strItem=overridden value", "subItem.intItem=5", "multiDocItem=edited value"], ) self.assertEqual(namespace.config.boolItem, False) self.assertEqual(namespace.config.floatItem, -67.1) self.assertEqual(namespace.config.strItem, "overridden value") self.assertEqual(namespace.config.subItem.intItem, 5) self.assertEqual(namespace.config.multiDocItem, "edited value")
"""Verify that order of overriding config values is left to right""" namespace = self.ap.parse_args( config=self.config, args=[DataPath, "--config", "floatItem=-67.1", "strItem=overridden value", "--config", "strItem=final value"], ) self.assertEqual(namespace.config.floatItem, -67.1) self.assertEqual(namespace.config.strItem, "final value")
"""Verify that incorrect names for config fields are caught""" with self.assertRaises(SystemExit): self.ap.parse_args(config=self.config, args=[DataPath, "--config", "missingItem=-67.1"], )
"""Test --show""" with capture() as out: self.ap.parse_args( config=self.config, args=[DataPath, "--show", "config", "data", "tasks", "run"], ) res = out[0] self.assertIn("config.floatItem", res) self.assertIn("config.subItem", res) self.assertIn("config.boolItem", res) self.assertIn("config.strItem", res) self.assertIn("config.multiDocItem", res) # Test show with exact config name and with one sided, embedded, and two sided globs for configStr in ("config.multiDocItem", "*ultiDocItem", "*ulti*Item", "*ultiDocI*"): with capture() as out: self.ap.parse_args(self.config, [DataPath, "--show", "config=" + configStr, "run"]) res = out[0] self.assertIn("config.multiDocItem", res)
with self.assertRaises(SystemExit): self.ap.parse_args(config=self.config, args=[DataPath, "--show", "config"], ) with self.assertRaises(SystemExit): self.ap.parse_args(config=self.config, args=[DataPath, "--show", "config=X"], )
# Test show with glob for single and multi-line doc strings for configStr, assertStr in ("*strItem*", "strDefault"), ("*multiDocItem", "multiLineDoc"): with capture() as out: self.ap.parse_args(self.config, [DataPath, "--show", "config=" + configStr, "run"]) stdout = out[0] stdoutList = stdout.rstrip().split("\n") self.assertGreater(len(stdoutList), 2) # at least 2 docstring lines (1st line is always a \n) # and 1 config parameter answer = [ans for ans in stdoutList if not ans.startswith("#")] # get rid of comment lines answer = [ans for ans in answer if ":NOIGNORECASE to prevent this" not in ans] self.assertEqual(len(answer), 2) # only 1 config item matches (+ 1 \n entry per doc string) self.assertIn(assertStr, answer[1])
with self.assertRaises(SystemExit): self.ap.parse_args(config=self.config, args=[DataPath, "--show", "badname", "run"], ) with self.assertRaises(SystemExit): self.ap.parse_args(config=self.config, args=[DataPath, "--show"], # no --show arguments )
# Test show with and without case sensitivity for configStr, shouldMatch in [("*multiDocItem*", True), ("*multidocitem*", True), ("*multidocitem*:NOIGNORECASE", False)]: with capture() as out: self.ap.parse_args(self.config, [DataPath, "--show", "config=" + configStr, "run"]) res = out[0]
if shouldMatch: self.assertIn("config.multiDocItem", res) else: self.assertNotIn("config.multiDocItem", res)
"""Test --configfile""" configFilePath = os.path.join(LocalDataPath, "argumentParserConfig.py") namespace = self.ap.parse_args( config=self.config, args=[DataPath, "--configfile", configFilePath], ) self.assertEqual(namespace.config.floatItem, -9e9) self.assertEqual(namespace.config.strItem, "set in override file")
"""Verify that order of setting values is with a mix of config file and config is left to right""" configFilePath = os.path.join(LocalDataPath, "argumentParserConfig.py") namespace = self.ap.parse_args( config=self.config, args=[DataPath, "--config", "floatItem=5.5", "--configfile", configFilePath, "--config", "strItem=value from cmd line"], ) self.assertEqual(namespace.config.floatItem, -9e9) self.assertEqual(namespace.config.strItem, "value from cmd line")
"""Verify that missing config override files are caught""" with self.assertRaises(SystemExit): self.ap.parse_args(config=self.config, args=[DataPath, "--configfile", "missingFile"], )
"""Test @file""" argPath = os.path.join(LocalDataPath, "args.txt") namespace = self.ap.parse_args( config=self.config, args=[DataPath, "@%s" % (argPath,)], ) self.assertEqual(len(namespace.id.idList), 1) self.assertEqual(namespace.config.floatItem, 4.7) self.assertEqual(namespace.config.strItem, "new value")
"""Test --loglevel""" for logLevel in ("trace", "debug", "Info", "WARN", "eRRoR", "fatal"): intLevel = getattr(lsstLog.Log, logLevel.upper()) print("testing logLevel=%r" % (logLevel,)) namespace = self.ap.parse_args( config=self.config, args=[DataPath, "--loglevel", logLevel], ) self.assertEqual(namespace.log.getLevel(), intLevel) self.assertFalse(hasattr(namespace, "loglevel"))
bazLevel = "TRACE" namespace = self.ap.parse_args( config=self.config, args=[DataPath, "--loglevel", logLevel, "foo.bar=%s" % (logLevel,), "baz=INFO", "baz=%s" % bazLevel, # test that later values override earlier values ], ) self.assertEqual(namespace.log.getLevel(), intLevel) self.assertEqual(lsstLog.Log.getLogger("foo.bar").getLevel(), intLevel) self.assertEqual(lsstLog.Log.getLogger("baz").getLevel(), getattr(lsstLog.Log, bazLevel))
with self.assertRaises(SystemExit): self.ap.parse_args(config=self.config, args=[DataPath, "--loglevel", "1234"], )
with self.assertRaises(SystemExit): self.ap.parse_args(config=self.config, args=[DataPath, "--loglevel", "INVALID_LEVEL"], )
"""Test handling of $PIPE_x_ROOT environment variables, where x is INPUT, CALIB or OUTPUT """ os.environ["PIPE_INPUT_ROOT"] = DataPath namespace = self.ap.parse_args( config=self.config, args=["."], ) self.assertEqual(namespace.input, os.path.abspath(DataPath)) self.assertEqual(namespace.calib, None)
os.environ["PIPE_CALIB_ROOT"] = DataPath namespace = self.ap.parse_args( config=self.config, args=["."], ) self.assertEqual(namespace.input, os.path.abspath(DataPath)) self.assertEqual(namespace.calib, os.path.abspath(DataPath))
os.environ.pop("PIPE_CALIB_ROOT", None) os.environ["PIPE_OUTPUT_ROOT"] = DataPath namespace = self.ap.parse_args( config=self.config, args=["."], ) self.assertEqual(namespace.input, os.path.abspath(DataPath)) self.assertEqual(namespace.calib, None) self.assertEqual(namespace.output, None)
"""Make sure bare help does not print an error message (ticket #3090) """ for helpArg in ("-h", "--help"): try: self.ap.parse_args( config=self.config, args=[helpArg], ) self.fail("should have raised SystemExit") except SystemExit as e: self.assertEqual(e.code, 0)
"""Test DatasetArgument basics""" dsTypeHelp = "help text for dataset argument" for name in (None, "--foo"): for default in (None, "raw"): argName = name if name is not None else "--id_dstype" ap = pipeBase.InputOnlyArgumentParser(name="argumentParser") dsType = pipeBase.DatasetArgument(name=name, help=dsTypeHelp, default=default) self.assertEqual(dsType.help, dsTypeHelp)
ap.add_id_argument("--id", dsType, "help text") namespace = ap.parse_args( config=self.config, args=[DataPath, argName, "calexp", "--id", "visit=2", ], ) self.assertEqual(namespace.id.datasetType, "calexp") self.assertEqual(len(namespace.id.idList), 1)
del namespace
if default is None: # make sure dataset type argument is required with self.assertRaises(SystemExit): ap.parse_args( config=self.config, args=[DataPath, "--id", "visit=2", ], ) else: namespace = ap.parse_args( config=self.config, args=[DataPath, "--id", "visit=2", ], ) self.assertEqual(namespace.id.datasetType, default) self.assertEqual(len(namespace.id.idList), 1)
"""Test DatasetArgument with a positional argument""" name = "foo" defaultDsTypeHelp = "dataset type to process from input data repository" ap = pipeBase.InputOnlyArgumentParser(name="argumentParser") dsType = pipeBase.DatasetArgument(name=name) self.assertEqual(dsType.help, defaultDsTypeHelp)
ap.add_id_argument("--id", dsType, "help text") namespace = ap.parse_args( config=self.config, args=[DataPath, "calexp", "--id", "visit=2", ], ) self.assertEqual(namespace.id.datasetType, "calexp") self.assertEqual(len(namespace.id.idList), 1)
# make sure dataset type argument is required with self.assertRaises(SystemExit): ap.parse_args( config=self.config, args=[DataPath, "--id", "visit=2", ], )
"""Test ConfigDatasetType with a config field that has a default value""" # default value for config field "dsType" is "calexp"; # use a different value as the default for the ConfigDatasetType # so the test can tell the difference name = "dsType" ap = pipeBase.InputOnlyArgumentParser(name="argumentParser") dsType = pipeBase.ConfigDatasetType(name=name)
ap.add_id_argument("--id", dsType, "help text") namespace = ap.parse_args( config=self.config, args=[DataPath, "--id", "visit=2", ], ) self.assertEqual(namespace.id.datasetType, "calexp") # default of config field dsType self.assertEqual(len(namespace.id.idList), 1)
"""Test ConfigDatasetType with a config field that has no default value""" name = "dsTypeNoDefault" ap = pipeBase.InputOnlyArgumentParser(name="argumentParser") dsType = pipeBase.ConfigDatasetType(name=name)
ap.add_id_argument("--id", dsType, "help text") # neither the argument nor the config field has a default, # so the user must specify the argument (or specify doMakeDataRefList=False # and post-process the ID list) with self.assertRaises(RuntimeError): ap.parse_args( config=self.config, args=[DataPath, "--id", "visit=2", ], )
"""Test output directories, specified in different ways""" parser = pipeBase.ArgumentParser(name="argumentParser") self.assertTrue(parser.requireOutput)
# Location of our working repository # We'll start by creating this, then use it as the basis for further tests # It's removed at the end of the try/finally block below repositoryPath = tempfile.mkdtemp() try: # Given input at DataPath, demonstrate that we can create a new # output repository at repositoryPath args = parser.parse_args(config=self.config, args=[DataPath, "--output", repositoryPath]) self.assertEqual(args.input, DataPath) self.assertEqual(args.output, repositoryPath) self.assertIsNone(args.rerun)
# Now based on our new output repository, demonstrate that we can create a rerun at rerun/foo args = parser.parse_args(config=self.config, args=[repositoryPath, "--rerun", "foo"]) self.assertEqual(args.input, repositoryPath) self.assertEqual(args.output, os.path.join(repositoryPath, "rerun", "foo")) self.assertEqual(args.rerun, ["foo"])
# Now check that that we can chain the above rerun into another args = parser.parse_args(config=self.config, args=[repositoryPath, "--rerun", "foo:bar"]) self.assertEqual(args.input, os.path.join(repositoryPath, "rerun", "foo")) self.assertEqual(args.output, os.path.join(repositoryPath, "rerun", "bar")) self.assertEqual(args.rerun, ["foo", "bar"])
# Finally, check that the above also works if the rerun directory already exists rerunPath = tempfile.mkdtemp(dir=os.path.join(repositoryPath, "rerun")) rerun = os.path.basename(rerunPath) try: args = parser.parse_args(config=self.config, args=[repositoryPath, "--rerun", rerun]) self.assertEqual(args.input, repositoryPath) self.assertEqual(args.output, os.path.join(repositoryPath, "rerun", rerun)) self.assertEqual(args.rerun, [rerun]) finally: shutil.rmtree(rerunPath)
finally: shutil.rmtree(repositoryPath)
# Finally, check that we raise an appropriate error if we don't specify an output location at all with self.assertRaises(SystemExit): parser.parse_args(config=self.config, args=[DataPath, ])
self.ap.addReuseOption(["a", "b", "c"]) namespace = self.ap.parse_args( config=self.config, args=[DataPath, "--reuse-outputs-from", "b"], ) self.assertEqual(namespace.reuse, ["a", "b"]) namespace = self.ap.parse_args( config=self.config, args=[DataPath, "--reuse-outputs-from", "all"], ) self.assertEqual(namespace.reuse, ["a", "b", "c"]) namespace = self.ap.parse_args( config=self.config, args=[DataPath], ) self.assertEqual(namespace.reuse, [])
lsst.utils.tests.init()
lsst.utils.tests.init() unittest.main() |