Skip to content

Rule

rule #

ConditionRule #

Bases: pydantic.BaseModel

Leaf: one tag compared to a value.

evaluate #

evaluate(row: pandas.Series) -> bool

Evaluate whether a metadata row (Series indexed by tag names) matches this rule.

Source code in src/imgnet/query/rule.py
def evaluate(self, row: pd.Series) -> bool:  # noqa: PLR0912, PLR0911
    """Evaluate whether a metadata row (Series indexed by tag names) matches this rule."""
    tag_value = row.get(self.tag)
    if tag_value is None:
        return False
    if pd.isna(tag_value):
        return False

    # Handles list-formatted values
    if isinstance(tag_value, str):
        if tag_value.strip().startswith(
            "["
        ) and tag_value.strip().endswith("]"):
            matches = re.findall(
                r"""(['"])(.*?)\1|([^'",\s\[\]]+)""", tag_value
            )
            tag_value = [m[1] if m[1] else m[2] for m in matches]
        else:
            tag_value = [tag_value.strip()]

    match self.comparison:
        case "==" | "=":
            patterns = self.value
            if isinstance(self.value, str):
                patterns = [self.value]
            for token in tag_value:
                for pattern in patterns:
                    if re.search(pattern, token):
                        return True
            return False

        case "!=":
            patterns = self.value
            if isinstance(self.value, str):
                patterns = [self.value]
            for token in tag_value:
                for pattern in patterns:
                    if re.search(pattern, token):
                        return False
            return True

        case ">" | "<" | ">=" | "<=":
            op_fn = NUMERIC_OPS[self.comparison]
            if isinstance(self.value, list):
                msg = f"{self.comparison} comparison only compatible with numeric arguments, not list."
                raise ValueError(msg)
            for token in tag_value:
                if token == "" or token is None or pd.isna(token):
                    return False
                try:
                    if not op_fn(float(token), float(self.value)):
                        return False
                except ValueError as exc:
                    msg = (
                        f"'{self.comparison}' comparisons only support numeric values."
                        f"\nInput: {self.tag}: {tag_value}, {self.comparison} {self.value}"
                    )
                    raise ValueError(msg) from exc
            return True

BoolRule #

Bases: pydantic.BaseModel

Composite: AND / OR of two subtrees.

evaluate #

evaluate(row: pandas.Series) -> bool

Evaluate row with AND/OR of the two subtrees.

Source code in src/imgnet/query/rule.py
def evaluate(self, row: pd.Series) -> bool:
    """Evaluate ``row`` with AND/OR of the two subtrees."""
    if self.op == "AND":
        return self.left.evaluate(row) and self.right.evaluate(row)
    elif self.op == "OR":
        return self.left.evaluate(row) or self.right.evaluate(row)
    else:
        msg = f"Invalid operator: {self.op}"
        raise ValueError(msg)

RuleTransformer #

Bases: lark.Transformer

Builds a tree without modality; start applies modality in one pass.