Skip to content

Commit 65c0a65

Browse files
Spike out DSL extension for annotation existence
1 parent ddacceb commit 65c0a65

File tree

1 file changed

+21
-0
lines changed

1 file changed

+21
-0
lines changed

src/phoenix/trace/dsl/filter.py

+21
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from sqlalchemy.orm.util import AliasedClass
1414
from sqlalchemy.sql.expression import Select
1515
from typing_extensions import TypeAlias, TypeGuard, assert_never
16+
from sqlalchemy import case, literal
1617

1718
import phoenix.trace.v1 as pb
1819
from phoenix.db import models
@@ -31,6 +32,10 @@
3132
r"""\b((annotations|evals)\[(".*?"|'.*?')\][.](label|score))\b"""
3233
)
3334

35+
EVAL_NAME_PATTERN = re.compile(
36+
r"""\b((annotations|evals)\[(\".*?\"|'.*?')\])\b"""
37+
)
38+
3439

3540
@dataclass(frozen=True)
3641
class AliasedAnnotationRelation:
@@ -46,16 +51,19 @@ class AliasedAnnotationRelation:
4651
table: AliasedClass[models.SpanAnnotation] = field(init=False, repr=False)
4752
_label_attribute_alias: str = field(init=False, repr=False)
4853
_score_attribute_alias: str = field(init=False, repr=False)
54+
_exists_attribute_alias: str = field(init=False, repr=False)
4955

5056
def __post_init__(self) -> None:
5157
table_alias = f"span_annotation_{self.index}"
5258
alias_id = uuid4().hex
5359
label_attribute_alias = f"{table_alias}_label_{alias_id}"
5460
score_attribute_alias = f"{table_alias}_score_{alias_id}"
61+
exists_attribute_alias = f"{table_alias}_exists_{alias_id}"
5562

5663
table = aliased(models.SpanAnnotation, name=table_alias)
5764
object.__setattr__(self, "_label_attribute_alias", label_attribute_alias)
5865
object.__setattr__(self, "_score_attribute_alias", score_attribute_alias)
66+
object.__setattr__(self, "_exists_attribute_alias", exists_attribute_alias)
5967
object.__setattr__(self, "table", table)
6068

6169
@property
@@ -66,6 +74,9 @@ def attributes(self) -> typing.Iterator[tuple[str, Mapped[typing.Any]]]:
6674
"""
6775
yield self._label_attribute_alias, self.table.label
6876
yield self._score_attribute_alias, self.table.score
77+
yield self._exists_attribute_alias, case(
78+
(self.table.id.is_not(None), literal(True))
79+
)
6980

7081
def attribute_alias(self, attribute: AnnotationAttribute) -> str:
7182
"""
@@ -555,6 +566,7 @@ def _validate_expression(
555566
isinstance(node, (ast.BoolOp, ast.Compare))
556567
or isinstance(node, ast.UnaryOp)
557568
and isinstance(node.op, ast.Not)
569+
or _is_annotation(node)
558570
):
559571
continue
560572
elif (
@@ -792,6 +804,15 @@ def _apply_eval_aliasing(
792804
eval_aliases[annotation_name] = eval_alias
793805
alias_name = eval_alias.attribute_alias(annotation_attribute)
794806
source = source.replace(annotation_expression, alias_name)
807+
808+
for match in EVAL_NAME_PATTERN.finditer(source):
809+
annotation_expression, annotation_type, quoted_eval_name = match.groups()
810+
annotation_name = quoted_eval_name[1:-1]
811+
if (eval_alias := eval_aliases.get(annotation_name)) is None:
812+
eval_alias = AliasedAnnotationRelation(index=len(eval_aliases), name=annotation_name)
813+
eval_aliases[annotation_name] = eval_alias
814+
alias_name = eval_alias._exists_attribute_alias
815+
source = source.replace(annotation_expression, alias_name)
795816
return source, tuple(eval_aliases.values())
796817

797818

0 commit comments

Comments
 (0)