Source code for dae.query_variants.attributes_query_inheritance
# pylint: disable=too-few-public-methods
import functools
import operator
from typing import Any
from lark import Lark, Transformer
from dae.variants.attributes import Inheritance
from .attributes_query import get_bit_and_str
INHERITANCE_QUERY_GRAMMAR = r"""
reference: "reference"
mendelian: "mendelian"
denovo: "denovo"
possible_denovo: "possible_denovo"
omission: "omission"
possible_omission: "possible_omission"
other: "other"
missing: "missing"
unknown: "unknown"
?primitive: reference
| mendelian
| denovo
| possible_denovo
| omission
| possible_omission
| other
| missing
| unknown
negative_primitive: "not" primitive
atom: primitive
| negative_primitive
atomlist: (atom "," )* atom [","]
all: "all"i "(" atomlist ")"
any: "any"i "(" atomlist ")"
logical_or: atom ("or" atom)+
logical_and: atom ("and" atom)+
expression: atom
| all
| any
| logical_or
| logical_and
%import common.WS
%ignore WS
"""
inheritance_parser = Lark(INHERITANCE_QUERY_GRAMMAR, start="expression")
PrimitiveType = Primitive | NegPrimitive
[docs]
class Expression:
def __init__(self, expression: str):
self.expression = expression
def __str__(self) -> str:
return self.expression
[docs]
class InheritanceTransformer(Transformer):
"""No idea what this class is supposed to do. If you know please edit."""
def __init__(
self, attr_name: str,
*args: Any,
use_bit_and_function: bool = True,
**kwargs: Any,
):
super().__init__(*args, **kwargs)
self.attr_name = attr_name
self.use_bit_and_function = use_bit_and_function
self.inheritance_mask = 16383
[docs]
def possible_denovo(self, _items: list) -> Primitive:
return Primitive(Inheritance.possible_denovo.value)
[docs]
def possible_omission(self, _items: list) -> Primitive:
return Primitive(Inheritance.possible_omission.value)
[docs]
def reference(self, _items: list) -> Primitive:
return Primitive(Inheritance.reference.value)
[docs]
def mendelian(self, _items: list) -> Primitive:
return Primitive(Inheritance.mendelian.value)
[docs]
def primitive(self, items: list) -> Primitive:
assert len(items) == 1
return Primitive(Inheritance.from_name(items[0]).value)
[docs]
def negative_primitive(self, items: list) -> PrimitiveType:
assert len(items) == 1
assert isinstance(items[0], Primitive)
return NegPrimitive(items[0].value)
[docs]
def atom(self, items: list) -> PrimitiveType:
assert len(items) == 1
assert isinstance(items[0], (Primitive, NegPrimitive))
return items[0]
[docs]
def atomlist(self, items: list) -> Primitive:
atom_values = [atom.value for atom in items]
mask = functools.reduce(operator.or_, atom_values, 0)
return Primitive(mask)
[docs]
def all(self, items: list) -> Expression:
assert len(items) == 1
assert isinstance(items[0], Primitive)
mask = items[0].value
bit_op = get_bit_and_str(mask, self.attr_name,
self.use_bit_and_function)
return Expression(f"{bit_op} = {mask}")
[docs]
def any(self, items: list) -> Expression:
assert len(items) == 1
assert isinstance(items[0], Primitive)
mask = items[0].value
bit_op = get_bit_and_str(mask, self.attr_name,
self.use_bit_and_function)
return Expression(f"{bit_op} != 0")
def _process_list(self, items: list) -> list[str]:
expressions: list[str] = []
for atom in items:
bit_op = get_bit_and_str(atom.value, self.attr_name,
self.use_bit_and_function)
if isinstance(atom, Primitive):
expressions.append(
f"{bit_op} != 0")
elif isinstance(atom, NegPrimitive):
expressions.append(
f"{bit_op} = 0")
elif isinstance(atom, Expression):
expressions.append(atom.expression)
else:
raise ValueError(f"unexpected expression {atom}")
return expressions
[docs]
def logical_or(self, items: list) -> Expression:
expressions = self._process_list(items)
return Expression(" OR ".join(expressions))
[docs]
def logical_and(self, items: list) -> Expression:
expressions = self._process_list(items)
return Expression(" AND ".join(expressions))
[docs]
def expression(self, items: list) -> Expression:
"""Construct an Expression from items."""
if len(items) == 1 and isinstance(items[0], Primitive):
mask = items[0].value
bit_op = get_bit_and_str(mask, self.attr_name,
self.use_bit_and_function)
return Expression(f"{bit_op} != 0")
if len(items) == 1 and isinstance(items[0], NegPrimitive):
mask = items[0].value
bit_op = get_bit_and_str(mask, self.attr_name,
self.use_bit_and_function)
return Expression(f"{bit_op} = 0")
if len(items) == 1 and isinstance(items[0], Expression):
return items[0]
raise NotImplementedError