Coverage for tests/test_plotImageSubtractionCutouts.py: 17%
234 statements
« prev ^ index » next coverage.py v7.5.1, created at 2024-05-18 12:10 +0000
« prev ^ index » next coverage.py v7.5.1, created at 2024-05-18 12:10 +0000
1# This file is part of analysis_ap.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (https://www.lsst.org).
6# See the COPYRIGHT file at the top-level directory of this distribution
7# for details of code ownership.
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation, either version 3 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program. If not, see <https://www.gnu.org/licenses/>.
22import os
23import pickle
24import sys
25import tempfile
26import unittest
28import lsst.afw.table
29import lsst.geom
30import lsst.meas.base.tests
31import lsst.utils.tests
32import numpy as np
33import pandas as pd
34import PIL
35from lsst.analysis.ap import plotImageSubtractionCutouts
36from lsst.meas.algorithms import SourceDetectionTask
38# Sky center chosen to test metadata annotations (3-digit RA and negative Dec).
39skyCenter = lsst.geom.SpherePoint(245.0, -45.0, lsst.geom.degrees)
41# A two-row mock APDB DiaSource table.
42DATA = pd.DataFrame(
43 data={
44 "diaSourceId": [506428274000265570, 527736141479149732],
45 "ra": [skyCenter.getRa().asDegrees()+0.0001, skyCenter.getRa().asDegrees()-0.0001],
46 "dec": [skyCenter.getDec().asDegrees()+0.0001, skyCenter.getDec().asDegrees()-0.001],
47 "detector": [50, 60],
48 "visit": [1234, 5678],
49 "instrument": ["TestMock", "TestMock"],
50 "band": ['r', 'g'],
51 "psfFlux": [1234.5, 1234.5],
52 "psfFluxErr": [123.5, 123.5],
53 "snr": [10.0, 11.0],
54 "psfChi2": [40.0, 50.0],
55 "psfNdata": [10, 100],
56 "apFlux": [2222.5, 3333.4],
57 "apFluxErr": [222.5, 333.4],
58 "scienceFlux": [2222000.5, 33330000.4],
59 "scienceFluxErr": [22200.5, 333000.4],
60 "isDipole": [True, False],
61 "reliability": [0, 1.0],
62 # First diaSource has all flags set, and second diaSource has none
63 "slot_PsfFlux_flag": [1, 0],
64 "slot_PsfFlux_flag_noGoodPixels": [1, 0],
65 "slot_PsfFlux_flag_edge": [1, 0],
66 "slot_ApFlux_flag": [1, 0],
67 "slot_ApFlux_flag_apertureTruncated": [1, 0],
68 "ip_diffim_forced_PsfFlux_flag": [1, 0],
69 "ip_diffim_forced_PsfFlux_flag_noGoodPixels": [1, 0],
70 "ip_diffim_forced_PsfFlux_flag_edge": [1, 0],
71 "pixelFlags_edge": [1, 0],
72 "pixelFlags_interpolated": [1, 0],
73 "pixelFlags_interpolatedCenter": [1, 0],
74 "pixelFlags_saturated": [1, 0],
75 "pixelFlags_saturatedCenter": [1, 0],
76 "pixelFlags_cr": [1, 0],
77 "pixelFlags_crCenter": [1, 0],
78 "pixelFlags_bad": [1, 0],
79 "pixelFlags_suspect": [1, 0],
80 "pixelFlags_suspectCenter": [1, 0],
81 "slot_Centroid_flag": [1, 0],
82 "slot_Shape_flag": [1, 0],
83 "slot_Shape_flag_no_pixels": [1, 0],
84 "slot_Shape_flag_not_contained": [1, 0],
85 "slot_Shape_flag_parent_source": [1, 0],
86 }
87)
90def make_mock_catalog(image):
91 """Make a simple SourceCatalog from the image, containing Footprints.
92 """
93 schema = lsst.afw.table.SourceTable.makeMinimalSchema()
94 table = lsst.afw.table.SourceTable.make(schema)
95 detect = SourceDetectionTask()
96 return detect.run(table, image).sources
99class TestPlotImageSubtractionCutouts(lsst.utils.tests.TestCase):
100 """Test that PlotImageSubtractionCutoutsTask generates images and manifest
101 files correctly.
102 """
103 def setUp(self):
104 bbox = lsst.geom.Box2I(lsst.geom.Point2I(0, 0), lsst.geom.Point2I(100, 100))
105 # source at the center of the image
106 self.centroid = lsst.geom.Point2D(50, 50)
107 dataset = lsst.meas.base.tests.TestDataset(bbox, crval=skyCenter)
108 self.scale = 0.3 # arbitrary arcseconds/pixel
109 dataset.addSource(instFlux=1e5, centroid=self.centroid)
110 self.science, self.scienceCat = dataset.realize(
111 noise=1000.0, schema=dataset.makeMinimalSchema()
112 )
113 self.template, self.templateCat = dataset.realize(
114 noise=5.0, schema=dataset.makeMinimalSchema()
115 )
116 # A simple image difference to have something to plot.
117 self.difference = lsst.afw.image.ExposureF(self.science, deep=True)
118 self.difference.image -= self.template.image
120 def test_generate_image(self):
121 """Test that we get some kind of image out.
123 It's useful to have a person look at the output via:
124 im.show()
125 """
126 # output_path does nothing here, since we never write the file to disk.
127 cutouts = plotImageSubtractionCutouts.PlotImageSubtractionCutoutsTask(output_path="")
128 cutout = cutouts.generate_image(self.science, self.template, self.difference, skyCenter, self.scale)
129 with PIL.Image.open(cutout) as im:
130 # NOTE: uncomment this to show the resulting image.
131 # im.show()
132 # NOTE: the dimensions here are determined by the matplotlib figure
133 # size (in inches) and the dpi (default=100), plus borders.
134 self.assertEqual((im.height, im.width), (233, 630))
136 def test_generate_image_larger_cutout(self):
137 """A different cutout size: the resulting cutout image is the same
138 size but shows more pixels.
139 """
140 config = plotImageSubtractionCutouts.PlotImageSubtractionCutoutsTask.ConfigClass()
141 config.sizes = [100]
142 # output_path does nothing here, since we never write the file to disk.
143 cutouts = plotImageSubtractionCutouts.PlotImageSubtractionCutoutsTask(config=config, output_path="")
144 cutout = cutouts.generate_image(self.science, self.template, self.difference, skyCenter, self.scale)
145 with PIL.Image.open(cutout) as im:
146 # NOTE: uncomment this to show the resulting image.
147 # im.show()
148 # NOTE: the dimensions here are determined by the matplotlib figure
149 # size (in inches) and the dpi (default=100), plus borders.
150 self.assertEqual((im.height, im.width), (233, 630))
152 def test_generate_image_metadata(self):
153 """Test that we can add metadata to the image; it changes the height
154 a lot, and the width a little for the text boxes.
156 It's useful to have a person look at the output via:
157 im.show()
158 """
159 config = plotImageSubtractionCutouts.PlotImageSubtractionCutoutsTask.ConfigClass()
160 config.add_metadata = True
161 # output_path does nothing here, since we never write the file to disk.
162 cutouts = plotImageSubtractionCutouts.PlotImageSubtractionCutoutsTask(config=config, output_path="")
163 cutout = cutouts.generate_image(self.science,
164 self.template,
165 self.difference,
166 skyCenter,
167 self.scale,
168 source=DATA.iloc[0])
169 with PIL.Image.open(cutout) as im:
170 # NOTE: uncomment this to show the resulting image.
171 # im.show()
172 # NOTE: the dimensions here are determined by the matplotlib figure
173 # size (in inches) and the dpi (default=100), plus borders.
174 self.assertEqual((im.height, im.width), (343, 645))
176 # A cutout without any flags: the dimensions should be unchanged.
177 cutout = cutouts.generate_image(self.science,
178 self.template,
179 self.difference,
180 skyCenter,
181 self.scale,
182 source=DATA.iloc[1])
183 with PIL.Image.open(cutout) as im:
184 # NOTE: uncomment this to show the resulting image.
185 # im.show()
186 # NOTE: the dimensions here are determined by the matplotlib figure
187 # size (in inches) and the dpi (default=100), plus borders.
188 self.assertEqual((im.height, im.width), (343, 645))
190 def test_generate_image_multisize_cutouts_without_metadata(self):
191 """Multiple cutout sizes: the resulting image is larger in size
192 and contains cutouts of multiple sizes.
193 """
194 config = plotImageSubtractionCutouts.PlotImageSubtractionCutoutsTask.ConfigClass()
195 config.sizes = [32, 64]
196 # output_path does nothing here, since we never write the file to disk.
197 cutouts = plotImageSubtractionCutouts.PlotImageSubtractionCutoutsTask(config=config, output_path="")
198 cutout = cutouts.generate_image(self.science, self.template, self.difference, skyCenter, self.scale)
199 with PIL.Image.open(cutout) as im:
200 # NOTE: uncomment this to show the resulting image.
201 # im.show()
202 # NOTE: the dimensions here are determined by the matplotlib figure
203 # size (in inches) and the dpi (default=100), plus borders.
204 self.assertEqual((im.height, im.width), (450, 630))
206 def test_generate_image_multisize_cutouts_with_metadata(self):
207 """Test that we can add metadata to the image; it changes the height
208 a lot, and the width a little for the text boxes.
210 It's useful to have a person look at the output via:
211 im.show()
212 """
213 config = plotImageSubtractionCutouts.PlotImageSubtractionCutoutsTask.ConfigClass()
214 config.add_metadata = True
215 config.sizes = [32, 64]
216 # output_path does nothing here, since we never write the file to disk.
217 cutouts = plotImageSubtractionCutouts.PlotImageSubtractionCutoutsTask(config=config, output_path="")
218 cutout = cutouts.generate_image(self.science,
219 self.template,
220 self.difference,
221 skyCenter,
222 self.scale,
223 source=DATA.iloc[0])
224 with PIL.Image.open(cutout) as im:
225 # NOTE: uncomment this to show the resulting image.
226 # im.show()
227 # NOTE: the dimensions here are determined by the matplotlib figure
228 # size (in inches) and the dpi (default=100), plus borders.
229 self.assertEqual((im.height, im.width), (576, 645))
231 # A cutout without any flags: the dimensions should be unchanged.
232 cutout = cutouts.generate_image(self.science,
233 self.template,
234 self.difference,
235 skyCenter,
236 self.scale,
237 source=DATA.iloc[1])
238 with PIL.Image.open(cutout) as im:
239 # NOTE: uncomment this to show the resulting image.
240 # im.show()
241 # NOTE: the dimensions here are determined by the matplotlib figure
242 # size (in inches) and the dpi (default=100), plus borders.
243 self.assertEqual((im.height, im.width), (576, 645))
245 def test_generate_image_and_save_as_numpy(self):
246 """Test that we can save an image as a .npy file and then read it back.
247 """
248 config = plotImageSubtractionCutouts.PlotImageSubtractionCutoutsTask.ConfigClass()
249 config.sizes = [100]
250 with tempfile.TemporaryDirectory() as path:
251 cutouts = plotImageSubtractionCutouts.PlotImageSubtractionCutoutsTask(config=config,
252 output_path=path)
253 cutouts.generate_image(self.science, self.template, self.difference, skyCenter, self.scale,
254 dia_source_id=506428274000265570, save_as_numpy=True)
255 numpy_dir_path = os.path.join(path, "raw_npy")
256 for file in os.listdir(numpy_dir_path):
257 image_with_channel = np.load(numpy_dir_path + "/" + file)
258 image = np.squeeze(image_with_channel, axis=0)
259 self.assertEqual((image.shape[0], image.shape[1]), (100, 100))
261 def test_write_images(self):
262 """Test that images get written to a temporary directory."""
263 butler = unittest.mock.Mock(spec=lsst.daf.butler.Butler)
264 # We don't care what the output images look like here, just that
265 # butler.get() returns an Exposure for every call.
266 butler.get.return_value = self.science
268 with tempfile.TemporaryDirectory() as path:
269 config = plotImageSubtractionCutouts.PlotImageSubtractionCutoutsTask.ConfigClass()
270 cutouts = plotImageSubtractionCutouts.PlotImageSubtractionCutoutsTask(config=config,
271 output_path=path)
272 result = cutouts.write_images(DATA, butler)
273 self.assertEqual(result, list(DATA["diaSourceId"]))
274 for file in ("images/506428274000260000/506428274000265570.png",
275 "images/527736141479140000/527736141479149732.png"):
276 filename = os.path.join(path, file)
277 self.assertTrue(os.path.exists(filename))
278 with PIL.Image.open(filename) as image:
279 self.assertEqual(image.format, "PNG")
281 def test_use_footprint(self):
282 """Test the use_footprint config option, generating a fake diaSrc
283 catalog that contains footprints that get used instead of config.sizes.
284 """
285 butler = unittest.mock.Mock(spec=lsst.daf.butler.Butler)
287 def mock_get(dataset, dataId, *args, **kwargs):
288 if "_diaSrc" in dataset:
289 # The science image is the only mock image with a source in it.
290 catalog = make_mock_catalog(self.science)
291 # Assign the matching source id to the detection.
292 match = DATA["visit"] == dataId["visit"]
293 catalog["id"] = DATA["diaSourceId"].to_numpy()[match][0]
294 return catalog
295 else:
296 return self.science
298 butler.get.side_effect = mock_get
300 with tempfile.TemporaryDirectory() as path:
301 config = plotImageSubtractionCutouts.PlotImageSubtractionCutoutsTask.ConfigClass()
302 config.use_footprint = True
303 cutouts = plotImageSubtractionCutouts.PlotImageSubtractionCutoutsTask(config=config,
304 output_path=path)
305 result = cutouts.write_images(DATA, butler)
306 self.assertEqual(result, list(DATA["diaSourceId"]))
307 for file in ("images/506428274000260000/506428274000265570.png",
308 "images/527736141479140000/527736141479149732.png"):
309 filename = os.path.join(path, file)
310 self.assertTrue(os.path.exists(filename))
311 with PIL.Image.open(filename) as image:
312 self.assertEqual(image.format, "PNG")
314 def test_write_images_exception(self):
315 """Test that write_images() catches errors in loading data."""
316 butler = unittest.mock.Mock(spec=lsst.daf.butler.Butler)
317 err = "Dataset not found"
318 butler.get.side_effect = LookupError(err)
320 with tempfile.TemporaryDirectory() as path:
321 config = plotImageSubtractionCutouts.PlotImageSubtractionCutoutsTask.ConfigClass()
322 cutouts = plotImageSubtractionCutouts.PlotImageSubtractionCutoutsTask(config=config,
323 output_path=path)
325 with self.assertLogs("lsst.plotImageSubtractionCutouts", "ERROR") as cm:
326 cutouts.write_images(DATA, butler)
327 self.assertIn(
328 "LookupError processing diaSourceId 506428274000265570: Dataset not found", cm.output[0]
329 )
330 self.assertIn(
331 "LookupError processing diaSourceId 527736141479149732: Dataset not found", cm.output[1]
332 )
334 def check_make_manifest(self, url_root, url_list):
335 """Check that make_manifest returns an appropriate DataFrame."""
336 data = [5, 10, 20]
337 config = plotImageSubtractionCutouts.PlotImageSubtractionCutoutsTask.ConfigClass()
338 config.url_root = url_root
339 # output_path does nothing here
340 cutouts = plotImageSubtractionCutouts.PlotImageSubtractionCutoutsTask(config=config, output_path="")
341 manifest = cutouts._make_manifest(data)
342 self.assertEqual(manifest["metadata:diaSourceId"].to_list(), [5, 10, 20])
343 self.assertEqual(manifest["location:1"].to_list(), url_list)
345 def test_make_manifest(self):
346 # check without an ending slash
347 root = "http://example.org/zooniverse"
348 url_list = [
349 f"{root}/images/5.png",
350 f"{root}/images/10.png",
351 f"{root}/images/20.png",
352 ]
353 self.check_make_manifest(root, url_list)
355 # check with an ending slash
356 root = "http://example.org/zooniverse/"
357 url_list = [
358 f"{root}images/5.png",
359 f"{root}images/10.png",
360 f"{root}images/20.png",
361 ]
362 self.check_make_manifest(root, url_list)
364 def test_pickle(self):
365 """Test that the task is pickleable (necessary for multiprocessing).
366 """
367 config = plotImageSubtractionCutouts.PlotImageSubtractionCutoutsTask.ConfigClass()
368 config.sizes = [63]
369 cutouts = plotImageSubtractionCutouts.PlotImageSubtractionCutoutsTask(config=config,
370 output_path="something")
371 other = pickle.loads(pickle.dumps(cutouts))
372 self.assertEqual(cutouts.config.sizes, other.config.sizes)
373 self.assertEqual(cutouts._output_path, other._output_path)
376class TestPlotImageSubtractionCutoutsMain(lsst.utils.tests.TestCase):
377 """Test the commandline interface main() function via mocks."""
378 def setUp(self):
379 datadir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "data/")
380 self.sqlitefile = os.path.join(datadir, "apdb.sqlite3")
381 self.repo = "/not/a/real/butler"
382 self.collection = "mockRun"
383 self.outputPath = "/an/output/path"
384 self.configFile = os.path.join(datadir, "plotImageSubtractionCutoutsConfig.py")
385 self.instrument = "LATISS"
387 # DM-39501: mock butler, until detector/visit are in APDB.
388 butlerPatch = unittest.mock.patch("lsst.daf.butler.Butler")
389 self._butler = butlerPatch.start()
390 self.addCleanup(butlerPatch.stop)
391 # DM-39501: mock unpacker, until detector/visit are in APDB.
392 import lsst.obs.lsst
393 universe = lsst.daf.butler.DimensionUniverse()
394 data_id = lsst.daf.butler.DataCoordinate.standardize({"instrument": self.instrument},
395 universe=universe)
396 # ObservationDimensionPacker is harder to use in a butler-less
397 # environment, so we need a temporary dependency on obs_lsst until
398 # this all goes away on DM-39501.
399 packer = lsst.obs.lsst.RubinDimensionPacker(data_id, is_exposure=False)
400 instrumentPatch = unittest.mock.patch.object(lsst.pipe.base.Instrument,
401 "make_default_dimension_packer",
402 return_value=packer)
403 self._instrument = instrumentPatch.start()
404 self.addCleanup(instrumentPatch.stop)
406 def test_main_args(self):
407 """Test typical arguments to main()."""
408 args = [
409 "plotImageSubtractionCutouts",
410 f"--sqlitefile={self.sqlitefile}",
411 f"--collections={self.collection}",
412 f"-C={self.configFile}",
413 f"--instrument={self.instrument}",
414 self.repo,
415 self.outputPath,
416 ]
417 with unittest.mock.patch.object(
418 plotImageSubtractionCutouts.PlotImageSubtractionCutoutsTask, "run", autospec=True
419 ) as run, unittest.mock.patch.object(sys, "argv", args):
420 plotImageSubtractionCutouts.main()
421 self.assertEqual(self._butler.call_args.args, (self.repo,))
422 self.assertEqual(
423 self._butler.call_args.kwargs, {"collections": [self.collection]}
424 )
425 # NOTE: can't easily test the `data` arg to run, as select_sources
426 # reads in a random order every time.
427 self.assertEqual(run.call_args.args[2], self._butler.return_value)
429 def test_main_args_no_collections(self):
430 """Test with no collections argument."""
431 args = [
432 "plotImageSubtractionCutouts",
433 f"--sqlitefile={self.sqlitefile}",
434 f"-C={self.configFile}",
435 f"--instrument={self.instrument}",
436 self.repo,
437 self.outputPath,
438 ]
439 with unittest.mock.patch.object(
440 plotImageSubtractionCutouts.PlotImageSubtractionCutoutsTask, "run", autospec=True
441 ) as run, unittest.mock.patch.object(sys, "argv", args):
442 plotImageSubtractionCutouts.main()
443 self.assertEqual(self._butler.call_args.args, (self.repo,))
444 self.assertEqual(self._butler.call_args.kwargs, {"collections": None})
445 self.assertIsInstance(run.call_args.args[1], pd.DataFrame)
446 self.assertEqual(run.call_args.args[2], self._butler.return_value)
448 def test_main_collection_list(self):
449 """Test passing a list of collections."""
450 collections = ["mock1", "mock2", "mock3"]
451 args = [
452 "plotImageSubtractionCutouts",
453 f"--sqlitefile={self.sqlitefile}",
454 f"--instrument={self.instrument}",
455 self.repo,
456 self.outputPath,
457 f"-C={self.configFile}",
458 "--collections",
459 ]
460 args.extend(collections)
461 with unittest.mock.patch.object(
462 plotImageSubtractionCutouts.PlotImageSubtractionCutoutsTask, "run", autospec=True
463 ) as run, unittest.mock.patch.object(sys, "argv", args):
464 plotImageSubtractionCutouts.main()
465 self.assertEqual(self._butler.call_args.args, (self.repo,))
466 self.assertEqual(
467 self._butler.call_args.kwargs, {"collections": collections}
468 )
469 self.assertIsInstance(run.call_args.args[1], pd.DataFrame)
470 self.assertEqual(run.call_args.args[2], self._butler.return_value)
472 def test_main_args_limit_offset(self):
473 """Test typical arguments to main()."""
474 args = [
475 "plotImageSubtractionCutouts",
476 f"--sqlitefile={self.sqlitefile}",
477 f"--collections={self.collection}",
478 f"-C={self.configFile}",
479 f"--instrument={self.instrument}",
480 "--all",
481 "--limit=5",
482 self.repo,
483 self.outputPath,
484 ]
485 with unittest.mock.patch.object(
486 plotImageSubtractionCutouts.PlotImageSubtractionCutoutsTask,
487 "write_images",
488 autospec=True,
489 return_value=[5]
490 ) as write_images, unittest.mock.patch.object(
491 plotImageSubtractionCutouts.PlotImageSubtractionCutoutsTask,
492 "write_manifest",
493 autospec=True
494 ) as write_manifest, unittest.mock.patch.object(sys, "argv", args):
495 plotImageSubtractionCutouts.main()
496 self.assertEqual(self._butler.call_args.args, (self.repo,))
497 self.assertEqual(
498 self._butler.call_args.kwargs, {"collections": [self.collection]}
499 )
500 self.assertIsInstance(write_images.call_args.args[1], pd.DataFrame)
501 self.assertEqual(write_images.call_args.args[2], self._butler.return_value)
502 # The test apdb contains 290 DiaSources, so we get the return of
503 # `write_images` (enforced as `5` above) 58 times.
504 self.assertEqual(write_manifest.call_args.args[1], 58*[5])
506 @unittest.skip("Mock and multiprocess don't mix: https://github.com/python/cpython/issues/100090")
507 def test_main_args_multiprocessing(self):
508 """Test running with multiprocessing.
509 """
510 args = [
511 "plotImageSubtractionCutouts",
512 f"--sqlitefile={self.sqlitefile}",
513 f"--collections={self.collection}",
514 "-j2",
515 f"-C={self.configFile}",
516 f"--instrument={self.instrument}",
517 self.repo,
518 self.outputPath,
519 ]
520 with unittest.mock.patch.object(
521 plotImageSubtractionCutouts.PlotImageSubtractionCutoutsTask, "run", autospec=True
522 ) as run, unittest.mock.patch.object(sys, "argv", args):
523 plotImageSubtractionCutouts.main()
524 self.assertEqual(self._butler.call_args.args, (self.repo,))
525 self.assertEqual(self._butler.call_args.kwargs, {"collections": [self.collection]})
526 # NOTE: can't easily test the `data` arg to run, as select_sources
527 # reads in a random order every time.
528 self.assertEqual(run.call_args.args[2], self._butler.return_value)
531class TestCutoutPath(lsst.utils.tests.TestCase):
532 def test_normal_path(self):
533 """Can the path manager handles non-chunked paths?
534 """
535 manager = plotImageSubtractionCutouts.CutoutPath("some/root/path")
536 path = manager(id=12345678)
537 self.assertEqual(path, "some/root/path/images/12345678.png")
539 def test_chunking(self):
540 """Can the path manager handle ids chunked into 10,000 file
541 directories?
542 """
543 manager = plotImageSubtractionCutouts.CutoutPath("some/root/path", chunk_size=10000)
544 path = manager(id=12345678)
545 self.assertEqual(path, "some/root/path/images/12340000/12345678.png")
547 def test_chunk_sizes(self):
548 """Test valid and invalid values for the chunk_size parameter.
549 """
550 with self.assertRaisesRegex(RuntimeError, "chunk_size must be a power of 10"):
551 plotImageSubtractionCutouts.CutoutPath("some/root/path", chunk_size=123)
553 with self.assertRaisesRegex(RuntimeError, "chunk_size must be a power of 10"):
554 plotImageSubtractionCutouts.CutoutPath("some/root/path", chunk_size=12300)
556 # should not raise
557 plotImageSubtractionCutouts.CutoutPath("some/root/path", chunk_size=1000)
558 plotImageSubtractionCutouts.CutoutPath("some/root/path", chunk_size=1000000)
561class TestMemory(lsst.utils.tests.MemoryTestCase):
562 pass
565def setup_module(module):
566 lsst.utils.tests.init()
569if __name__ == "__main__": 569 ↛ 570line 569 didn't jump to line 570, because the condition on line 569 was never true
570 lsst.utils.tests.init()
571 unittest.main()