gavo.adql.morphhelpers module

Helpers for morphing modules

class gavo.adql.morphhelpers.Morpher(morphers, earlyMorphers={})[source]

Bases: object

A class managing the process of morphing an ADQL expression.

It is constructed with a a dictionary of morphers; the keys are node types, the values morphing functions.

Morphing functions have the signature m(node, state) -> node. They should return the node if they do not with to change it. state is a State instance.

The main entry point is morph(origTree) -> state, tree. origTree is not modified, the return value can be flattened but can otherwise be severely damaged.

For special effects, there’s also earlyMorphers. These will be called when traversal reaches the node for the first time. If these return None, traversal continues as usual, if not, their result will be added to the tree and not further traversed. TODO: We don’t currently have anything requiring earlyMorphers. Do we want to drop the feature?

class gavo.adql.morphhelpers.State[source]

Bases: object

is a scratchpad for morphers to communicate state among themselves.

Append to warnings a necessary. Also, traverse keeps an attribute nodeStack in here letting elements look up its parent chain.

gavo.adql.morphhelpers.addNotToBooleanized(expr, operator, operand)[source]

prepends a NOT to expr if operator and operand suggest there should be one for ADQL integerized boolean expressions.

The function will return None for unknown combinations of operator and operand, and it will simply hand through Nones for expr, so calling functions can just return addNotToBooleanized(…).

gavo.adql.morphhelpers.analyzeFuncComp(node, acceptableOperators=['=', '!='])[source]

returns the (function, other operator) for a comparisonPredicate

This is regardless of the order of the comparison.

This will return None, None if

  • node isn’t a comparisonPredicate

  • the operator is not symmetric

  • none of the operators is a FunctionNode

gavo.adql.morphhelpers.booleanizeComparisons(node, state)[source]

turns a comparison expression that’s really a boolean expression into a boolean expression.

Actual morphers shouldn’t use that but rather get their parent from the stack and use its OVERRIDE_RESULT attribute. See the DISTANCE morpher for an example.

For several reasons, ufuncs like ivo_hasword can’t really do this. Instead, they call registerBooleanizer with the function name and callable that receives the function node, the operator, and the operand. If that function returns non-None, that result is used instead of the current node.

gavo.adql.morphhelpers.registerBooleanizer(funcName, handler)[source]

registers handler as a booleanizer for ADQL functions called funcName.

funcName must be all-uppercase for this to work. handler(node, operand, operator) is a function that receives a function node and the operand and operator of the comparison and either returns None to say it can’t handle it, or something else; that something else is what the entire comparison node is morphed into.

You can call multiple booleanizers for the same function; they will be tried in sequence. Hence, make sure you get your import sequences right if you do this.