Coverage for python/lsst/daf/butler/registry/queries/expressions/parser/treeVisitor.py: 98%
30 statements
« prev ^ index » next coverage.py v7.4.3, created at 2024-03-12 10:05 +0000
« prev ^ index » next coverage.py v7.4.3, created at 2024-03-12 10:05 +0000
1# This file is part of daf_butler.
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 software is dual licensed under the GNU General Public License and also
10# under a 3-clause BSD license. Recipients may choose which of these licenses
11# to use; please see the files gpl-3.0.txt and/or bsd_license.txt,
12# respectively. If you choose the GPL option then the following text applies
13# (but note that there is still no warranty even if you opt for BSD instead):
14#
15# This program is free software: you can redistribute it and/or modify
16# it under the terms of the GNU General Public License as published by
17# the Free Software Foundation, either version 3 of the License, or
18# (at your option) any later version.
19#
20# This program is distributed in the hope that it will be useful,
21# but WITHOUT ANY WARRANTY; without even the implied warranty of
22# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23# GNU General Public License for more details.
24#
25# You should have received a copy of the GNU General Public License
26# along with this program. If not, see <https://www.gnu.org/licenses/>.
28from __future__ import annotations
30__all__ = ["TreeVisitor"]
32from abc import abstractmethod
33from typing import TYPE_CHECKING, Generic, TypeVar
35if TYPE_CHECKING:
36 import astropy.time
38 from .exprTree import Node
41T = TypeVar("T")
44class TreeVisitor(Generic[T]):
45 """Definition of interface for visitor classes.
47 Visitors and tree node classes implement Visitor pattern for tree
48 traversal. Typical use case is to generate different representation
49 of the tree, e.g. transforming parsed tree into SQLAlchemy clause.
51 All methods of the class can (and most likely should) return the
52 "transformed" value of the visited node. This value will be returned
53 from the `Node.visit` method and it will also be passed as an argument
54 to other methods of the visitor.
55 """
57 @abstractmethod
58 def visitNumericLiteral(self, value: str, node: Node) -> T:
59 """Visit NumericLiteral node.
61 Parameters
62 ----------
63 value : `str`
64 The value associated with the visited node, the value is string,
65 exactly as it appears in the original expression. Depending on
66 use case it may need to be converted to `int` or `float`.
67 node : `Node`
68 Corresponding tree node, mostly useful for diagnostics.
69 """
71 @abstractmethod
72 def visitStringLiteral(self, value: str, node: Node) -> T:
73 """Visit StringLiteral node.
75 Parameters
76 ----------
77 value : `str`
78 The value associated with the visited node.
79 node : `Node`
80 Corresponding tree node, mostly useful for diagnostics.
81 """
83 @abstractmethod
84 def visitTimeLiteral(self, value: astropy.time.Time, node: Node) -> T:
85 """Visit TimeLiteral node.
87 Parameters
88 ----------
89 value : `astropy.time.Time`
90 The value associated with the visited node.
91 node : `Node`
92 Corresponding tree node, mostly useful for diagnostics.
93 """
95 @abstractmethod
96 def visitRangeLiteral(self, start: int, stop: int, stride: int | None, node: Node) -> T:
97 """Visit RangeLiteral node.
99 Parameters
100 ----------
101 start : `int`
102 Range starting value.
103 stop : `int`
104 Range final value.
105 stride : `int` or `None`
106 Stride, can be `None` if not specified (should be treated same
107 as 1).
108 node : `Node`
109 Corresponding tree node, mostly useful for diagnostics.
110 """
112 @abstractmethod
113 def visitIdentifier(self, name: str, node: Node) -> T:
114 """Visit Identifier node.
116 Parameters
117 ----------
118 name : `str`
119 Identifier name.
120 node : `Node`
121 Corresponding tree node, mostly useful for diagnostics.
122 """
124 @abstractmethod
125 def visitUnaryOp(self, operator: str, operand: T, node: Node) -> T:
126 """Visit UnaryOp node.
128 Parameters
129 ----------
130 operator : `str`
131 Operator name, e.g. "NOT" or "+".
132 operand : `object`
133 Operand, this object is returned by one of the methods of this
134 class as a result of transformation of some other tree node.
135 node : `Node`
136 Corresponding tree node, mostly useful for diagnostics.
137 """
139 @abstractmethod
140 def visitBinaryOp(self, operator: str, lhs: T, rhs: T, node: Node) -> T:
141 """Visit BinaryOp node.
143 Parameters
144 ----------
145 operator : `str`
146 Operator name, e.g. "NOT" or "+".
147 lhs : `object`
148 Left hand side operand, this object is returned by one of the
149 methods of this class as a result of transformation of some other
150 tree node.
151 rhs : `object`
152 Right hand side operand, this object is returned by one of the
153 methods of this class as a result of transformation of some other
154 tree node.
155 node : `Node`
156 Corresponding tree node, mostly useful for diagnostics.
157 """
159 @abstractmethod
160 def visitIsIn(self, lhs: T, values: list[T], not_in: bool, node: Node) -> T:
161 """Visit IsIn node.
163 Parameters
164 ----------
165 lhs : `object`
166 Left hand side operand, this object is returned by one of the
167 methods of this class as a result of transformation of some other
168 tree node.
169 values : `list` of `object`
170 Right hand side operand, list of objects returned by methods of
171 this class as a result of transformation of some other tree nodes.
172 not_in : `bool`
173 `True` for "NOT IN" expression.
174 node : `Node`
175 Corresponding tree node, mostly useful for diagnostics.
176 """
178 @abstractmethod
179 def visitParens(self, expression: T, node: Node) -> T:
180 """Visit Parens node.
182 Parameters
183 ----------
184 expression : `object`
185 Expression inside parentheses, this object is returned by one of
186 the methods of this class as a result of transformation of some
187 other tree node.
188 node : `Node`
189 Corresponding tree node, mostly useful for diagnostics.
190 """
192 @abstractmethod
193 def visitTupleNode(self, items: tuple[T, ...], node: Node) -> T:
194 """Visit TupleNode node.
196 Parameters
197 ----------
198 items : `tuple` of `object`
199 Expressions inside parentheses, tuple of objects returned by one
200 of the methods of this class as a result of transformation of
201 tuple items.
202 node : `Node`
203 Corresponding tree node, mostly useful for diagnostics.
204 """
206 def visitFunctionCall(self, name: str, args: list[T], node: Node) -> T:
207 """Visit FunctionCall node.
209 Parameters
210 ----------
211 name : `str`
212 Name of the function.
213 args : `list` of `object`
214 Arguments to function, list of objects returned by methods of
215 this class as a result of transformation of function arguments.
216 node : `Node`
217 Corresponding tree node, mostly useful for diagnostics.
219 Notes
220 -----
221 For now we only have to support one specific function ``POINT()``
222 and for that function we define special node type `PointNode`.
223 `FunctionCall` node type represents a generic function and regular
224 visitors do not handle generic function. This non-abstract method
225 is a common implementation for those visitors which raises an
226 exception.
227 """
228 raise ValueError(f"Unknown function '{name}' in expression")
230 @abstractmethod
231 def visitPointNode(self, ra: T, dec: T, node: Node) -> T:
232 """Visit PointNode node.
234 Parameters
235 ----------
236 ra, dec : `object`
237 Representation of 'ra' and 'dec' values, objects returned by
238 methods of this class as a result of transformation of function
239 arguments.
240 node : `Node`
241 Corresponding tree node, mostly useful for diagnostics.
242 """