Coverage for python/lsst/summit/extras/annotations.py: 37%
35 statements
« prev ^ index » next coverage.py v7.5.1, created at 2024-05-11 05:40 -0700
« prev ^ index » next coverage.py v7.5.1, created at 2024-05-11 05:40 -0700
1# This file is part of summit_extras.
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/>.
22from lsst.summit.extras.imageSorter import TAGS, ImageSorter
25def _idTrans(dataIdDictOrTuple: dict | tuple[int, int]) -> tuple[int, int]:
26 """Take a dataId and turn it into the internal tuple format."""
27 if isinstance(dataIdDictOrTuple, tuple): 27 ↛ 28line 27 didn't jump to line 28, because the condition on line 27 was never true
28 return dataIdDictOrTuple
29 elif isinstance(dataIdDictOrTuple, dict): 29 ↛ 32line 29 didn't jump to line 32, because the condition on line 29 was always true
30 return (dataIdDictOrTuple["dayObs"], dataIdDictOrTuple["seqNum"])
31 else:
32 raise RuntimeError(f"Failed to parse dataId {dataIdDictOrTuple}")
35class Annotations:
36 """Class for interfacing with annotations, as written by the
37 imageSorter.
38 """
40 def __init__(self, filename: str):
41 self.filename = filename
42 self.tags, self.notes = self._load(filename)
44 def _load(self, filename: str) -> tuple[dict, dict]:
45 """Load tags and notes from specified file."""
46 tags, notes = ImageSorter.loadAnnotations(filename)
47 return tags, notes
49 def getTags(self, dataId: dict | tuple[int, int]) -> str | None:
50 """Get the tags for a specified dataId.
52 Empty string means no tags, None means not examined"""
53 return self.tags.get(_idTrans(dataId), None)
55 def getNotes(self, dataId: dict | tuple[int, int]) -> str | None:
56 """Get the notes for the specified dataId."""
57 return self.notes.get(_idTrans(dataId), None)
59 def hasTags(self, dataId: dict | tuple[int, int], flags: str) -> bool | None:
60 """Check if a dataId has all the specificed tags"""
61 tag = self.getTags(dataId)
62 if tag is None: # not just 'if tag' becuase '' is not the same as None but both as False-y
63 return None
64 return all(i in tag for i in flags.upper())
66 def getListOfCheckedData(self) -> list:
67 """Return a list of all dataIds which have been examined."""
68 return sorted(list(self.tags.keys()))
70 def getListOfDataWithNotes(self) -> list:
71 """Return a list of all dataIds which have notes associated."""
72 return sorted(list(self.notes.keys()))
74 def isExamined(self, dataId: dict) -> bool:
75 """Check if the dataId has been examined or not."""
76 return _idTrans(dataId) in self.tags
78 def printTags(self) -> None:
79 """Display the list of tag definitions."""
80 print(TAGS)
82 def getIdsWithGivenTags(self, tags: str, exactMatches: bool = False) -> list:
83 if exactMatches:
84 return [
85 dId
86 for (dId, tag) in self.tags.items()
87 if (all(t in tag for t in tags.upper()) and (len(tags) == len(tag)))
88 ]
89 else:
90 return [dId for (dId, tag) in self.tags.items() if all(t in tag for t in tags.upper())]