LSST Applications g0f08755f38+c89d42e150,g1635faa6d4+b6cf076a36,g1653933729+a8ce1bb630,g1a0ca8cf93+4c08b13bf7,g28da252d5a+f33f8200ef,g29321ee8c0+0187be18b1,g2bbee38e9b+9634bc57db,g2bc492864f+9634bc57db,g2cdde0e794+c2c89b37c4,g3156d2b45e+41e33cbcdc,g347aa1857d+9634bc57db,g35bb328faa+a8ce1bb630,g3a166c0a6a+9634bc57db,g3e281a1b8c+9f2c4e2fc3,g414038480c+077ccc18e7,g41af890bb2+e740673f1a,g5fbc88fb19+17cd334064,g7642f7d749+c89d42e150,g781aacb6e4+a8ce1bb630,g80478fca09+f8b2ab54e1,g82479be7b0+e2bd23ab8b,g858d7b2824+c89d42e150,g9125e01d80+a8ce1bb630,g9726552aa6+10f999ec6a,ga5288a1d22+065360aec4,gacf8899fa4+9553554aa7,gae0086650b+a8ce1bb630,gb58c049af0+d64f4d3760,gbd46683f8f+ac57cbb13d,gc28159a63d+9634bc57db,gcf0d15dbbd+e37acf7834,gda3e153d99+c89d42e150,gda6a2b7d83+e37acf7834,gdaeeff99f8+1711a396fd,ge2409df99d+cb1e6652d6,ge79ae78c31+9634bc57db,gf0baf85859+147a0692ba,gf3967379c6+02b11634a5,w.2024.45
LSST Data Management Base Package
Loading...
Searching...
No Matches
_plugins.py
Go to the documentation of this file.
1# This file is part of pipe_tasks.
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/>.
21
22from __future__ import annotations
23
24__all__ = ("PluginsRegistry", "plugins")
25
26from enum import Enum, auto
27from collections.abc import Callable
28from typing import TYPE_CHECKING, Generator
29
30if TYPE_CHECKING:
31 from numpy.typing import NDArray
32 from collections.abc import Mapping
33
34 PLUGIN_TYPE = Callable[[NDArray, NDArray, Mapping[str, int]], NDArray]
35
36
37class PluginType(Enum):
38 """Enumeration to mark the type of data a plugin expects to work on"""
39
40 CHANNEL = auto()
41 """A plugin of this type expects to work on an individual channel
42 from a partial region of a mosaic, such as a `patch`.
43 """
44 PARTIAL = auto()
45 """A pluging that expects to work on a 3 channel image that is
46 a partial region of a mosaic, such as a `patch`.
47 """
48 FULL = auto()
49 """FULL plugins operate on a 3 channel image corresponding to
50 a complete mosaic.
51 """
52
53
55 """A class to serve as a registry for all pretty picture manipulation
56 plugins.
57
58 This class should not be instantiated directly other than the one
59 instantiation in this module.
60
61 example
62 -------
63 Using this registry to create a plugin would look somehting like the
64 following.
65
66 @plugins.register(1, PluginType.PARTIAL)
67 def fixNoData(
68 image: NDArray,
69 mask: NDArray,
70 maskDict: Mapping[str, int]
71 ) -> NDArray:
72 m = (mask & 2 ** maskDict["NO_DATA"]).astype(bool)
73 for i in range(3):
74 image[:, :, i] = cv2.inpaint(
75 image[:, :, i].astype(np.float32),
76 m.astype(np.uint8),
77 3,
78 cv2.INPAINT_TELEA
79 ).astype(image.dtype)
80 return image
81
82 """
83
84 def __init__(self) -> None:
85 self._full_values: list[tuple[float, PLUGIN_TYPE]] = []
86 self._partial_values: list[tuple[float, PLUGIN_TYPE]] = []
87 self._channel_values: list[tuple[float, PLUGIN_TYPE]] = []
88
89 def channel(self) -> Generator[PLUGIN_TYPE, None, None]:
90 yield from (func for _, func in self._channel_values)
91
92 def partial(self) -> Generator[PLUGIN_TYPE, None, None]:
93 yield from (func for _, func in self._partial_values)
94
95 def full(self) -> Generator[PLUGIN_TYPE, None, None]:
96 yield from (func for _, func in self._full_values)
97
98 def register(self, order: float, kind: PluginType) -> Callable:
99 """Register a plugin which is to be run when producing a
100 pretty picture.
101
102 parameters
103 ----------
104 order : `float`
105 This determines in what order plugins will be run. For
106 example, if plugin A specifies order 2, and plugin B
107 specifies order 1, and both are the same ``kind`` of
108 plugin type, plugin B will be run before plugin A.
109 kind : `PluginType`
110 This specifies what data the registered plugin expects
111 to run on, a channel, a partial image, or a full mosaic.
112
113 """
114
115 def wrapper(
116 func: Callable[[NDArray, NDArray, Mapping[str, int]], NDArray],
117 ) -> Callable[[NDArray, NDArray, Mapping[str, int]], NDArray]:
118 match kind:
119 case PluginType.PARTIAL:
120 self._partial_values.append((order, func))
121 case PluginType.FULL:
122 self._full_values.append((order, func))
123 case PluginType.CHANNEL:
124 self._channel_values.append((order, func))
125 return func
126
127 return wrapper
128
129
131"""
132This is the only instance of the plugin registry there should be. Users
133should import from here and use the register method as a decorator to
134register any plugins. Or, preferably, add them to this file to avoid
135needing any other import time logic elsewhere.
136"""
Generator[PLUGIN_TYPE, None, None] full(self)
Definition _plugins.py:95
Generator[PLUGIN_TYPE, None, None] partial(self)
Definition _plugins.py:92
Generator[PLUGIN_TYPE, None, None] channel(self)
Definition _plugins.py:89
Callable register(self, float order, PluginType kind)
Definition _plugins.py:98