diff --git a/.wordlist.txt b/.wordlist.txt
index e87e60ee5..be6d87c94 100644
--- a/.wordlist.txt
+++ b/.wordlist.txt
@@ -35,6 +35,7 @@ DescribeStreamSummary
disambiguity
Dockerfile
expr
+exponentiate
Eval
eval
endswith
@@ -127,6 +128,8 @@ Secret
ShardIteratorType
Signifier
SnapshotData
+sqrt
+Sqrt
Stddev
Subprocessor
SubscribeToShard
diff --git a/docs/api.yml b/docs/api.yml
index 6a9c6a509..24b809c40 100644
--- a/docs/api.yml
+++ b/docs/api.yml
@@ -108,8 +108,10 @@ sidebar:
- "api-reference/expressions/lit"
- "api-reference/expressions/not"
- "api-reference/expressions/now"
+ - "api-reference/expressions/repeat"
- "api-reference/expressions/typeof"
- "api-reference/expressions/when"
+ - "api-reference/expressions/zip"
- slug: "api-reference/expressions/dt"
title: "Datetime Expressions"
@@ -146,7 +148,10 @@ sidebar:
- "api-reference/expressions/num/abs"
- "api-reference/expressions/num/ceil"
- "api-reference/expressions/num/floor"
+ - "api-reference/expressions/num/log"
+ - "api-reference/expressions/num/pow"
- "api-reference/expressions/num/round"
+ - "api-reference/expressions/num/sqrt"
- "api-reference/expressions/num/to_string"
- slug: "api-reference/expressions/str"
diff --git a/docs/examples/api-reference/expressions/basic.py b/docs/examples/api-reference/expressions/basic.py
index 3a27c2e82..249c6bc68 100644
--- a/docs/examples/api-reference/expressions/basic.py
+++ b/docs/examples/api-reference/expressions/basic.py
@@ -1,7 +1,7 @@
from datetime import datetime
import pytest
-from typing import Optional
+from typing import Optional, List
import pandas as pd
@@ -176,8 +176,58 @@ def test_now():
{"birthdate": [datetime(1997, 12, 24), datetime(2001, 1, 21), None]}
)
assert expr.eval(df, schema={"birthdate": Optional[datetime]}).tolist() == [
- 26,
+ 27,
23,
pd.NA,
]
# /docsnip
+
+
+def test_repeat():
+ # docsnip repeat
+ from fennel.expr import repeat, col
+
+ # docsnip-highlight next-line
+ expr = repeat(col("x"), col("y"))
+
+ assert expr.typeof(schema={"x": bool, "y": int}) == List[bool]
+
+ # can be evaluated with a dataframe
+ df = pd.DataFrame({"x": [True, False, True], "y": [1, 2, 3]})
+ assert expr.eval(df, schema={"x": bool, "y": int}).tolist() == [
+ [True],
+ [False, False],
+ [True, True, True],
+ ]
+ # /docsnip
+
+
+def test_zip():
+ # docsnip zip
+ from fennel.lib.schema import struct
+ from fennel.expr import col
+
+ @struct
+ class MyStruct:
+ a: int
+ b: float
+
+ # docsnip-highlight next-line
+ expr = MyStruct.zip(a=col("x"), b=col("y"))
+
+ expected = List[MyStruct]
+ schema = {"x": List[int], "y": List[float]}
+ assert expr.matches_type(expected, schema)
+
+ # note that output is truncated to the length of the shortest list
+ df = pd.DataFrame(
+ {"x": [[1, 2], [3, 4], []], "y": [[1.0, 2.0], [3.0], [4.0]]}
+ )
+ assert expr.eval(
+ df, schema={"x": List[int], "y": List[float]}
+ ).tolist() == [
+ [MyStruct(a=1, b=1.0), MyStruct(a=2, b=2.0)],
+ [MyStruct(a=3, b=3.0)],
+ [],
+ ]
+ # /docsnip
diff --git a/docs/examples/api-reference/expressions/num.py b/docs/examples/api-reference/expressions/num.py
index 08125dc3e..1d3b78648 100644
--- a/docs/examples/api-reference/expressions/num.py
+++ b/docs/examples/api-reference/expressions/num.py
@@ -1,4 +1,5 @@
import pytest
+import numpy as np
from typing import Optional
import pandas as pd
@@ -146,3 +147,79 @@ def test_to_string():
pd.NA,
]
# /docsnip
+
+
+def test_sqrt():
+ # docsnip sqrt
+ from fennel.expr import col
+
+ # docsnip-highlight next-line
+ expr = col("x").num.sqrt()
+
+ assert expr.typeof(schema={"x": int}) == float
+ assert expr.typeof(schema={"x": Optional[int]}) == Optional[float]
+ assert expr.typeof(schema={"x": float}) == float
+ assert expr.typeof(schema={"x": Optional[float]}) == Optional[float]
+
+ df = pd.DataFrame({"x": pd.Series([1.1, -2.3, 4.0])})
+ assert expr.eval(df, schema={"x": Optional[float]}).tolist() == [
+ 1.0488088481701516,
+ pd.NA, # this is nan in pandas, sqrt of negative number
+ 2.0,
+ ]
+ # /docsnip
+
+
+def test_log():
+ # docsnip log
+ from fennel.expr import col
+
+ # docsnip-highlight next-line
+ expr = col("x").num.log(base=2.0)
+
+ assert expr.typeof(schema={"x": int}) == float
+ assert expr.typeof(schema={"x": Optional[int]}) == Optional[float]
+ assert expr.typeof(schema={"x": float}) == float
+ assert expr.typeof(schema={"x": Optional[float]}) == Optional[float]
+
+ df = pd.DataFrame({"x": pd.Series([1.1, -2.3, 4.0])})
+ assert expr.eval(df, schema={"x": Optional[float]}).tolist() == [
+ 0.13750352374993502,
+ pd.NA, # nan in pandas, log of negative number
+ 2.0,
+ ]
+ # /docsnip
+
+
+def test_pow():
+ # docsnip pow
+ from fennel.expr import col, lit
+
+ # docsnip-highlight next-line
+ expr = col("x").num.pow(lit(2))
+
+ assert expr.typeof(schema={"x": int}) == int
+ assert expr.typeof(schema={"x": Optional[int]}) == Optional[int]
+ assert expr.typeof(schema={"x": float}) == float
+ assert expr.typeof(schema={"x": Optional[float]}) == Optional[float]
+
+ df = pd.DataFrame({"x": pd.Series([1, 2, 4])})
+ assert expr.eval(df, schema={"x": int}).tolist() == [
+ 1,
+ 4,
+ 16,
+ ]
+
+ # negative integer exponent raises error if base is also an integer
+ with pytest.raises(Exception):
+ expr = lit(2).num.pow(lit(-2))
+ expr.eval(df, schema={"x": int})
+
+ # but works if either base or exponent is a float
+ expr = lit(2).num.pow(lit(-2.0))
+ assert expr.eval(df, schema={"x": int}).tolist() == [
+ 0.25,
+ 0.25,
+ 0.25,
+ ]
+ # /docsnip
diff --git a/docs/pages/api-reference/expressions/num/log.md b/docs/pages/api-reference/expressions/num/log.md
new file mode 100644
index 000000000..26f1aad6f
--- /dev/null
+++ b/docs/pages/api-reference/expressions/num/log.md
@@ -0,0 +1,34 @@
+---
+title: Log
+order: 0
+status: published
+---
+
+### Log
+
+Function in `num` namespace to get the logarithm of a number.
+
+#### Parameters
+
+The base of the logarithm. By default, the base is set to `e` (Euler's number).
+
+
+#### Returns
+
+Returns an expression object denoting the logarithm of the input data. The
+data type of the resulting expression is `float` if the input was `int` or
+`float` and `Optional[float]` if the input was `Optional[int]` or
+`Optional[float]`.
+
+For negative numbers, the result is `NaN` (Not a Number).
+
+
+
+
+
+#### Errors
+
+Error during `typeof` or `eval` if the input expression is not of type int,
+float, optional int or optional float.
+
\ No newline at end of file
diff --git a/docs/pages/api-reference/expressions/num/pow.md b/docs/pages/api-reference/expressions/num/pow.md
new file mode 100644
index 000000000..a6a0c5e2c
--- /dev/null
+++ b/docs/pages/api-reference/expressions/num/pow.md
@@ -0,0 +1,45 @@
+---
+title: Pow
+order: 0
+status: published
+---
+
+### Pow
+
+Function in `num` namespace to exponentiate a number.
+
+#### Parameters
+
+The exponent to which the base is raised - expected to be a numeric expression.
+
+
+#### Returns
+
+Returns an expression object denoting the result of the exponentiation.
+
+The base data type of the resulting expression is `int` if both the base and
+exponent are `int`, otherwise it is `float`.
+
+If any of the base or exponent is `Optional`, the resulting expression is
+also `Optional` of the base data type.
+
+
+
+
+
+#### Errors
+
+
+Error during `typeof` or `eval` if the input expression is not of type int,
+float, optional int or optional float.
+
+
+
+
+A runtime error will be raised if the exponent is a negative integer and the
+base is also an integer.
+
+In such cases, it's advised to convert either the base or the exponent to be a
+float.
+
diff --git a/docs/pages/api-reference/expressions/num/sqrt.md b/docs/pages/api-reference/expressions/num/sqrt.md
new file mode 100644
index 000000000..710cd16b6
--- /dev/null
+++ b/docs/pages/api-reference/expressions/num/sqrt.md
@@ -0,0 +1,31 @@
+---
+title: Sqrt
+order: 0
+status: published
+---
+
+### Sqrt
+
+Function in `num` namespace to get the square root of a number.
+
+#### Returns
+
+Returns an expression object denoting the square root of the input data.
+
+The data type of the resulting expression is `float` if the input is `int` or
+`float` and `Optional[float]` if the input is `Optional[int]` or `Optional[float]`.
+
+
+:::info
+The square root of a negative number is represented as `NaN` in the output.
+:::
+
+
+
+
+#### Errors
+
+Error during `typeof` or `eval` if the input expression is not of type int,
+float, optional int or optional float.
+
diff --git a/docs/pages/api-reference/expressions/repeat.md b/docs/pages/api-reference/expressions/repeat.md
new file mode 100644
index 000000000..721ee5a58
--- /dev/null
+++ b/docs/pages/api-reference/expressions/repeat.md
@@ -0,0 +1,39 @@
+---
+title: Repeat
+order: 0
+status: published
+---
+### Repeat
+
+Repeat an expression `n` times to create a list.
+
+#### Parameters
+
+The expression to repeat.
+
+
+
+The number of times to repeat the value - can evaluate to a different count for
+each row.
+
+
+
+
+
+
+#### Returns
+
+Returns an expression object denoting the result of the repeat expression.
+
+
+
+#### Errors
+
+An error is thrown if the `by` expression is not of type int.
+In addition, certain types (e.g. lists) are not supported as input for `value`.
+
+
+
+An error is thrown if the `by` expression evaluates to a negative integer.
+
diff --git a/docs/pages/api-reference/expressions/zip.md b/docs/pages/api-reference/expressions/zip.md
new file mode 100644
index 000000000..8e741d3eb
--- /dev/null
+++ b/docs/pages/api-reference/expressions/zip.md
@@ -0,0 +1,48 @@
+---
+title: Zip
+order: 0
+status: published
+---
+### Zip
+
+Zip two or more lists into a list of structs.
+
+#### Parameters
+
+The struct to hold the zipped values. Unlike other top level expressions,
+`zip` is written as `Struct.zip(kwarg1=expr1, kwarg2=expr2, ...)`.
+
+
+
+A dictionary of key-value pairs where the key is the name of the field in the
+struct and the value is the expression to zip.
+
+Expressions are expected to evaluate to lists of a type that can be converted to
+the corresponding field type in the struct.
+
+
+
+
+
+
+#### Returns
+
+Returns an expression object denoting the result of the zip expression.
+
+
+:::info
+When zipping lists of unequal length, similar to Python's zip function, the
+resulting list will be truncated to the length of the shortest list, possibly
+zero.
+:::
+
+#### Errors
+
+An error is thrown if the types of the lists to zip are not compatible with the
+field types in the struct.
+
+
+
+An error is thrown if the expressions to zip don't evaluate to lists.
+
diff --git a/fennel/CHANGELOG.md b/fennel/CHANGELOG.md
index 66cb5034d..842a87103 100644
--- a/fennel/CHANGELOG.md
+++ b/fennel/CHANGELOG.md
@@ -1,5 +1,8 @@
# Changelog
+## [1.5.63] - 2024-12-24
+- Add support for zip, repeat, pow, log, and sqrt expressions
+
## [1.5.62] - 2024-12-16
- Fix casting for empty dataframes.
diff --git a/fennel/client_tests/test_complex_autogen_extractor.py b/fennel/client_tests/test_complex_autogen_extractor.py
index b869b2388..36f63599f 100644
--- a/fennel/client_tests/test_complex_autogen_extractor.py
+++ b/fennel/client_tests/test_complex_autogen_extractor.py
@@ -346,7 +346,10 @@ def test_complex_auto_gen_extractors(client):
assert extracted_df["RiderFeatures.dl_state"].to_list() == ["US", "Unknown"]
assert extracted_df["RiderFeatures.is_us_dl"].to_list() == [True, False]
- age_years = datetime.now(timezone.utc).year - 2000
+ age_years = (
+ datetime.now() - datetime(2000, 1, 1, 0, 0, 0)
+ ).total_seconds() / (60 * 60 * 24 * 365)
+ age_years = int(age_years + 0.001)
assert extracted_df["RiderFeatures.age_years"].to_list() == [30, age_years]
assert extracted_df["RiderFeatures.dl_state_population"].to_list() == [
328200000,
diff --git a/fennel/client_tests/test_expr.py b/fennel/client_tests/test_expr.py
index fd01f545a..32f84f032 100644
--- a/fennel/client_tests/test_expr.py
+++ b/fennel/client_tests/test_expr.py
@@ -89,7 +89,7 @@ class UserInfoFeatures:
"Rachel",
pd.NA,
]
- assert df["UserInfoFeatures.age"].tolist() == [54, 44, 34, 26, 23, pd.NA]
+ assert df["UserInfoFeatures.age"].tolist() == [55, 44, 34, 27, 23, pd.NA]
assert df["UserInfoFeatures.country"].tolist() == [
"India",
"USA",
@@ -132,10 +132,10 @@ class UserInfoFeatures:
pd.NA,
]
assert df["UserInfoFeatures.age"].tolist() == [
- 53,
+ 54,
43,
33,
- 25,
+ 26,
22,
pd.NA,
]
diff --git a/fennel/dtypes/dtypes.py b/fennel/dtypes/dtypes.py
index e01f4f879..0756a9de6 100644
--- a/fennel/dtypes/dtypes.py
+++ b/fennel/dtypes/dtypes.py
@@ -86,6 +86,28 @@ def make_struct_expr(cls, **kwargs):
return make_struct(fields, cls)
+def eq(cls):
+ names = [field.name for field in dataclasses.fields(cls)]
+
+ def eq_impl(self, other):
+ print("inside dataclass eq")
+ # verify that the other is a struct of the same type
+ for name in names:
+ if not hasattr(other, name):
+ return False
+ if getattr(self, name) != getattr(other, name):
+ return False
+ return True
+
+ return eq_impl
+
+
+def zip_expr(cls, **kwargs):
+ from fennel.expr.expr import zip
+
+ return zip(cls, kwargs)
+
+
def struct(cls):
for name, member in inspect.getmembers(cls):
if inspect.isfunction(member) and name in cls.__dict__:
@@ -143,7 +165,11 @@ def struct(cls):
setattr(cls, FENNEL_STRUCT_DEPENDENCIES_SRC_CODE, dependency_code)
cls.as_json = as_json
cls.expr = partial(make_struct_expr, cls)
- return dataclasses.dataclass(cls)
+ cls.zip = partial(zip_expr, cls)
+ decorator = dataclasses.dataclass(eq=False)
+ cls = decorator(cls)
+ cls.__eq__ = eq(cls)
+ return cls
# ---------------------------------------------------------------------
diff --git a/fennel/expr/__init__.py b/fennel/expr/__init__.py
index 43e0dc3e8..24f518aa3 100644
--- a/fennel/expr/__init__.py
+++ b/fennel/expr/__init__.py
@@ -1,12 +1,13 @@
from fennel.expr.expr import (
col,
- lit,
- when,
- make_struct,
- var,
datetime,
- from_epoch,
- now,
Expr,
+ from_epoch,
InvalidExprException,
+ lit,
+ make_struct,
+ now,
+ repeat,
+ var,
+ when,
)
diff --git a/fennel/expr/expr.py b/fennel/expr/expr.py
index b41ece1cb..327856404 100644
--- a/fennel/expr/expr.py
+++ b/fennel/expr/expr.py
@@ -3,6 +3,7 @@
from enum import Enum
import copy
import json
+import math
from dataclasses import dataclass
from typing import Any, Callable, Dict, Type, Optional
import pandas as pd
@@ -486,6 +487,20 @@ class NumToStr(MathOp):
pass
+class Sqrt(MathOp):
+ pass
+
+
+@dataclass
+class Pow(MathOp):
+ exponent: Expr
+
+
+@dataclass
+class Log(MathOp):
+ base: float
+
+
class MathNoop(MathOp):
pass
@@ -511,6 +526,15 @@ def floor(self) -> _Number:
def to_string(self) -> _String:
return _String(_Number(self, NumToStr()), StringNoop())
+ def sqrt(self) -> _Number:
+ return _Number(self, Sqrt())
+
+ def pow(self, exponent: Expr) -> _Number:
+ return _Number(self, Pow(exponent))
+
+ def log(self, base: float = math.e) -> _Number:
+ return _Number(self, Log(base))
+
#########################################################
# String Functions
@@ -1063,6 +1087,37 @@ def __str__(self) -> str:
return f"{self.left} {self.op} {self.right}"
+class Repeat(Expr):
+ def __init__(self, value: Expr, by: Expr):
+ self.value = make_expr(value)
+ self.by = make_expr(by)
+ if not isinstance(self.value, Expr):
+ raise InvalidExprException(
+ "`value` in repeat can only be an expression but got %s instead"
+ % self.value
+ )
+ if not isinstance(self.by, Expr):
+ raise InvalidExprException(
+ "`by` in repeat expected to be an expression but got %s instead"
+ % self.by
+ )
+ super(Repeat, self).__init__()
+
+ def __str__(self) -> str:
+ return f"repeat({self.value}, {self.by})"
+
+
+class Zip(Expr):
+ def __init__(self, struct_type: Type, fields: Dict[str, Expr]):
+ self.struct_type = struct_type
+ self.fields = {k: make_expr(v) for k, v in fields.items()}
+ super(Zip, self).__init__()
+
+ def __str__(self) -> str:
+ kwargs = [f"{k}={v}" for k, v in self.fields.items()]
+ return f"{self.struct_type}.zip({', '.join(kwargs)})"
+
+
class When(Expr):
def __init__(self, expr: Expr, root: Optional[Expr] = None):
self.expr = make_expr(expr)
@@ -1085,7 +1140,7 @@ def when(self, expr: Expr) -> When:
self._chained_when = When(expr, self.root) # type: ignore
return self._chained_when # type: ignore
- def otherwise(self, expr: Expr) -> Otherwise:
+ def otherwise(self, expr: Expr) -> When:
self._otherwise = Otherwise(make_expr(expr), self.root) # type: ignore
return self._otherwise # type: ignore
@@ -1202,6 +1257,15 @@ def make_struct(fields: Dict[str, Expr], type: Type) -> Expr:
return MakeStruct(fields, type)
+def zip(struct_type: Type, fields: Dict[str, Expr]) -> Expr:
+ fields = {k: make_expr(v) for k, v in fields.items()}
+ return Zip(struct_type, fields)
+
+
+def repeat(value: Expr, by: Expr) -> Expr:
+ return Repeat(value, by)
+
+
def from_epoch(duration: Expr, unit: str | TimeUnit) -> _DateTime:
duration = make_expr(duration)
unit = TimeUnit.from_string(unit)
diff --git a/fennel/expr/serializer.py b/fennel/expr/serializer.py
index 784a2445b..22cf9f958 100644
--- a/fennel/expr/serializer.py
+++ b/fennel/expr/serializer.py
@@ -47,6 +47,9 @@
MathNoop,
Round,
Ceil,
+ Sqrt,
+ Pow,
+ Log,
NumToStr,
Abs,
Floor,
@@ -67,6 +70,8 @@
DictLen,
DictNoop,
DateTimeNoop,
+ Zip,
+ Repeat,
)
@@ -234,6 +239,18 @@ def visitNumber(self, obj):
expr.math_fn.fn.CopyFrom(proto.MathOp(floor=proto.Floor()))
elif isinstance(obj.op, NumToStr):
expr.math_fn.fn.CopyFrom(proto.MathOp(to_string=proto.ToString()))
+ elif isinstance(obj.op, Sqrt):
+ expr.math_fn.fn.CopyFrom(proto.MathOp(sqrt=proto.Sqrt()))
+ elif isinstance(obj.op, Pow):
+ expr.math_fn.fn.CopyFrom(
+ proto.MathOp(
+ pow=proto.Pow(exponent=self.visit(obj.op.exponent))
+ )
+ )
+ elif isinstance(obj.op, Log):
+ expr.math_fn.fn.CopyFrom(
+ proto.MathOp(log=proto.Log(base=obj.op.base))
+ )
else:
raise InvalidExprException("invalid number operation: %s" % obj.op)
expr.math_fn.operand.CopyFrom(self.visit(obj.operand))
@@ -503,6 +520,30 @@ def visitNow(self, obj):
expr.now.CopyFrom(proto.Now())
return expr
+ def visitZip(self, obj):
+ expr = proto.Expr()
+ for field, value in obj.fields.items():
+ field_expr = expr.zip.fields.get_or_create(field)
+ field_expr.CopyFrom(self.visit(value))
+
+ # Ensure get_datatype returns a correct protobuf message of type StructType
+ dtype = get_datatype(obj.struct_type)
+ if dtype.struct_type is None:
+ raise InvalidExprException(
+ "invalid zip: expected struct_type to be a StructType, found {}".format(
+ dtype
+ )
+ )
+ expr.zip.struct_type.CopyFrom(dtype.struct_type)
+ return expr
+
+ def visitRepeat(self, obj):
+ expr = proto.Expr()
+ expr.repeat.CopyFrom(
+ proto.Repeat(expr=self.visit(obj.value), count=self.visit(obj.by))
+ )
+ return expr
+
def val_as_json(val: Any) -> str:
if isinstance(val, str):
diff --git a/fennel/expr/test_expr.py b/fennel/expr/test_expr.py
index 4b9a02b16..e7caeb598 100644
--- a/fennel/expr/test_expr.py
+++ b/fennel/expr/test_expr.py
@@ -8,11 +8,12 @@
from fennel.datasets import dataset
from fennel.dtypes.dtypes import struct
-from fennel.expr import col, when, lit, now
+from fennel.expr import col, when, lit, now, var
from fennel.expr.expr import (
TimeUnit,
from_epoch,
make_struct,
+ repeat,
)
from fennel.expr.visitor import ExprPrinter, FetchReferences
from fennel.expr.serializer import ExprSerializer
@@ -437,10 +438,13 @@ def compare_values(received, expected, dtype):
), f"Expected {e}, got {r} for field {field.name} in struct {act}"
else:
compare_values([r], [e], field.type)
+ elif hasattr(dtype, "__origin__") and dtype.__origin__ is list:
+ for act, exp in zip(received, expected):
+ compare_values(act, exp, dtype.__args__[0])
else:
assert (
list(received) == expected
- ), f"Expected {expected}, got {received} for dtype {dtype}"
+ ), f"Expected {expected} of type {dtype}, got {received} of type {type(received)}"
def check_test_case(test_case: ExprTestCase):
@@ -475,7 +479,10 @@ def check_test_case(test_case: ExprTestCase):
)
else:
assert (
- test_case.expr.typeof(test_case.schema) == test_case.expected_dtype
+ test_case.expr.matches_type(
+ test_case.expected_dtype, test_case.schema
+ )
+ # test_case.expr.typeof(test_case.schema) == test_case.expected_dtype
)
# Test eval
@@ -538,6 +545,25 @@ class A:
z: str
+@struct
+class Point:
+ x: int
+ y: int
+
+
+@struct
+class PointF:
+ x: Optional[float]
+ y: Optional[float]
+
+
+@struct
+class Point3D:
+ x: int
+ y: int
+ z: int
+
+
@struct
class Nested:
a: A
@@ -1138,16 +1164,277 @@ def test_parse_str_to_and_from_datetime():
assert ret.tolist() == df["a"].tolist()
-def test_make_struct():
+def test_repeat():
+ cases = [
+ ExprTestCase(
+ expr=repeat(lit(1), 3),
+ df=pd.DataFrame({"a": [1, 2, 3]}),
+ schema={"a": int},
+ display="REPEAT(1, 3)",
+ refs=set(),
+ eval_result=[[1, 1, 1], [1, 1, 1], [1, 1, 1]],
+ expected_dtype=List[int],
+ proto_json=None,
+ ),
+ ExprTestCase(
+ expr=repeat(col("a"), 3),
+ df=pd.DataFrame({"a": [1, 2, 3]}),
+ schema={"a": int},
+ display='REPEAT(col("a"), 3)',
+ refs={"a"},
+ eval_result=[[1, 1, 1], [2, 2, 2], [3, 3, 3]],
+ expected_dtype=List[int],
+ proto_json=None,
+ ),
+ ExprTestCase(
+ expr=repeat(col("a"), lit(3)),
+ df=pd.DataFrame({"a": [True, False, True]}),
+ schema={"a": bool},
+ display='REPEAT(col("a"), 3)',
+ refs={"a"},
+ eval_result=[
+ [True, True, True],
+ [False, False, False],
+ [True, True, True],
+ ],
+ expected_dtype=List[bool],
+ proto_json=None,
+ ),
+ ExprTestCase(
+ expr=repeat(col("a"), lit(3)),
+ df=pd.DataFrame({"a": [1.0, None, 3.0]}),
+ schema={"a": Optional[float]},
+ display='REPEAT(col("a"), 3)',
+ refs={"a"},
+ eval_result=[
+ [1.0, 1.0, 1.0],
+ [pd.NA, pd.NA, pd.NA],
+ [3.0, 3.0, 3.0],
+ ],
+ expected_dtype=List[Optional[float]],
+ proto_json=None,
+ ),
+ ExprTestCase(
+ expr=repeat(col("a"), lit(0)),
+ df=pd.DataFrame({"a": [1, 2, 3]}),
+ schema={"a": int},
+ display='REPEAT(col("a"), 0)',
+ refs={"a"},
+ eval_result=[[], [], []],
+ expected_dtype=List[int],
+ proto_json=None,
+ ),
+ ]
+ for case in cases:
+ check_test_case(case)
+
+ # repeat with negative count
+ expr = repeat(col("a"), lit(-1))
+ with pytest.raises(BaseException):
+ expr.eval(pd.DataFrame({"a": [1, 2, 3]}), {"a": int})
+
+
+def test_sqrt():
+ cases = [
+ ExprTestCase(
+ expr=lit(4).num.sqrt(),
+ df=pd.DataFrame({"a": [1, 4, 9]}),
+ schema={"a": int},
+ display="SQRT(4)",
+ refs=set(),
+ eval_result=[2.0, 2.0, 2.0],
+ expected_dtype=float,
+ proto_json=None,
+ ),
+ ExprTestCase(
+ expr=col("a").num.sqrt(),
+ df=pd.DataFrame({"a": [1, 4, 9]}),
+ schema={"a": int},
+ display='SQRT(col("a"))',
+ refs={"a"},
+ eval_result=[1.0, 2.0, 3.0],
+ expected_dtype=float,
+ proto_json=None,
+ ),
+ ]
+
+ for case in cases:
+ check_test_case(case)
+
+
+def test_pow():
+ cases = [
+ ExprTestCase(
+ expr=lit(2).num.pow(lit(3)),
+ df=pd.DataFrame({"a": [1, 2, 3]}),
+ schema={"a": int},
+ display="POW(2, 3)",
+ refs=set(),
+ eval_result=[8, 8, 8],
+ expected_dtype=int,
+ proto_json=None,
+ ),
+ ExprTestCase(
+ expr=col("a").num.pow(lit(3)),
+ df=pd.DataFrame({"a": [1.0, 2.0, 3.0]}),
+ schema={"a": float},
+ display='POW(col("a"), 3)',
+ refs={"a"},
+ eval_result=[1.0, 8.0, 27.0],
+ expected_dtype=float,
+ proto_json=None,
+ ),
+ ExprTestCase(
+ expr=col("a").num.pow(lit(-2.0)),
+ df=pd.DataFrame({"a": [1, 2, 3]}),
+ schema={"a": int},
+ display='POW(col("a"), -2.0)',
+ refs={"a"},
+ eval_result=[1.0, 0.25, 0.1111111111111111],
+ expected_dtype=float,
+ proto_json=None,
+ ),
+ ]
+ for case in cases:
+ check_test_case(case)
+
+ expr = col("a").num.pow(lit(-2))
+ with pytest.raises(Exception):
+ expr.eval(pd.DataFrame({"a": [1, 2, 3]}), {"a": int})
+
+
+def test_log():
+ cases = [
+ ExprTestCase(
+ expr=lit(100).num.log(10.0),
+ df=pd.DataFrame({"a": [1, 2, 3]}),
+ schema={"a": int},
+ display="LOG(100, base=10.0)",
+ refs=set(),
+ eval_result=[2.0, 2.0, 2.0],
+ expected_dtype=float,
+ proto_json=None,
+ ),
+ ExprTestCase(
+ expr=col("a").num.log(),
+ df=pd.DataFrame({"a": [1, 2, 3]}),
+ schema={"a": int},
+ display='LOG(col("a"), base=2.718281828459045)',
+ refs={"a"},
+ eval_result=[0.0, 0.6931471805599453, 1.0986122886681098],
+ expected_dtype=float,
+ proto_json=None,
+ ),
+ ]
+ for case in cases:
+ check_test_case(case)
+
+
+def test_zip():
cases = [
# Make a struct
ExprTestCase(
- expr=(
- make_struct(
- {"x": col("a"), "y": col("a") + col("b"), "z": "constant"},
- A,
- )
+ expr=A.zip(
+ x=col("a"),
+ y=col("b"),
+ z=col("b").list.map("e", var("e").num.to_string()),
+ ),
+ df=pd.DataFrame({"a": [[1, 2], [3], []], "b": [[4, 5], [6], []]}),
+ schema={"a": List[int], "b": List[int]},
+ display="""ZIP(A, x=col("a"), y=col("b"), z=LIST_MAP(col("b"), "e", TO_STRING(var("e"))))""",
+ refs={"a", "b"},
+ eval_result=[
+ [A(1, 4, "4"), A(2, 5, "5")],
+ [A(3, 6, "6")],
+ [],
+ ],
+ expected_dtype=List[A],
+ proto_json=None,
+ ),
+ ExprTestCase(
+ expr=Point.zip(x=col("a"), y=col("b")).list.map(
+ "s",
+ var("s").struct.get("x") / (lit(1) + var("s").struct.get("y")),
+ ),
+ df=pd.DataFrame({"a": [[1, 2], [3], []], "b": [[4, 5], [6], []]}),
+ schema={"a": List[int], "b": List[int]},
+ display="""LIST_MAP(ZIP(Point, x=col("a"), y=col("b")), "s", (var("s").x / (1 + var("s").y)))""",
+ refs={"a", "b"},
+ eval_result=[
+ [0.2, 0.3333333333333333],
+ [3.0 / 7.0],
+ [],
+ ],
+ expected_dtype=List[float],
+ proto_json=None,
+ ),
+ ExprTestCase(
+ expr=PointF.zip(
+ x=col("a"),
+ y=col("b").list.map(
+ "n",
+ when(var("n") > lit(5))
+ .then(var("n") * lit(2))
+ .otherwise(lit(None)),
+ ),
+ ),
+ df=pd.DataFrame({"a": [[1, 2], [3], []], "b": [[4, 5], [6], []]}),
+ schema={"a": List[int], "b": List[int]},
+ display="""ZIP(PointF, x=col("a"), y=LIST_MAP(col("b"), "n", WHEN (var("n") > 5) THEN (var("n") * 2) ELSE null))""",
+ refs={"a", "b"},
+ eval_result=[
+ [PointF(1.0, None), PointF(2.0, None)],
+ [PointF(3.0, 12.0)],
+ [],
+ ],
+ expected_dtype=List[PointF],
+ proto_json=None,
+ ),
+ # zip works with the shortest list
+ ExprTestCase(
+ expr=Point.zip(x=col("a"), y=col("b")),
+ df=pd.DataFrame(
+ {"a": [[1, 2], [3], []], "b": [[4, 5, 6], [6], [7]]}
+ ),
+ schema={"a": List[int], "b": List[int]},
+ display="""ZIP(Point, x=col("a"), y=col("b"))""",
+ refs={"a", "b"},
+ eval_result=[
+ [Point(1, 4), Point(2, 5)],
+ [Point(3, 6)],
+ [],
+ ],
+ expected_dtype=List[Point],
+ proto_json=None,
+ ),
+ # same as before but with three lists
+ ExprTestCase(
+ expr=Point3D.zip(x=col("a"), y=col("b"), z=col("c")),
+ df=pd.DataFrame(
+ {
+ "a": [[1, 2], [3], []],
+ "b": [[4, 5, 6], [6, 8], [7, 9, 10]],
+ "c": [[8, 9], [10], [11]],
+ }
),
+ schema={"a": List[int], "b": List[int], "c": List[int]},
+ display="""ZIP(Point3D, x=col("a"), y=col("b"), z=col("c"))""",
+ refs={"a", "b", "c"},
+ eval_result=[[Point3D(1, 4, 8), A(2, 5, 9)], [A(3, 6, 10)], []],
+ expected_dtype=List[Point3D],
+ proto_json=None,
+ ),
+ ]
+
+ for case in cases:
+ check_test_case(case)
+
+
+def test_make_struct():
+ cases = [
+ # Make a struct
+ ExprTestCase(
+ expr=A.expr(x=col("a"), y=col("a") + col("b"), z="constant"),
df=pd.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]}),
schema={"a": int, "b": int},
display="""STRUCT(x=col("a"), y=(col("a") + col("b")), z="constant")""",
@@ -1162,17 +1449,10 @@ def test_make_struct():
),
# Make a nested struct
ExprTestCase(
- expr=(
- make_struct(
- {
- "a": make_struct(
- {"x": col("a"), "y": col("b"), "z": col("c")}, A
- ),
- "b": make_struct({"p": col("d"), "q": col("e")}, B),
- "c": col("f"),
- },
- Nested,
- )
+ expr=Nested.expr(
+ a=A.expr(x=col("a"), y=col("b"), z=col("c")),
+ b=B.expr(p=col("d"), q=col("e")),
+ c=col("f"),
),
df=pd.DataFrame(
{
@@ -1207,6 +1487,11 @@ def test_make_struct():
for case in cases:
check_test_case(case)
+ # construct a case that won't compile
+ expr = Point.zip(x=col("a"), y=col("b") * lit(2.2))
+ with pytest.raises(Exception):
+ expr.typeof({"a": int, "b": int})
+
def test_from_epoch():
cases = [
diff --git a/fennel/expr/test_invalid_expr.py b/fennel/expr/test_invalid_expr.py
index 23e9d07cb..3b4697ada 100644
--- a/fennel/expr/test_invalid_expr.py
+++ b/fennel/expr/test_invalid_expr.py
@@ -97,7 +97,6 @@ def test_invalid_parse():
expr = col("a").str.parse(int)
df = pd.DataFrame({"a": ['"A"', '"B"', '"C"']})
expr.eval(df, {"a": str})
- assert (
- str(e.value)
- == "failed to evaluate expression: failed to convert polars array to fennel array for type 'Int'"
+ assert str(e.value).startswith(
+ "failed to evaluate expression: failed to convert polars array of type Int64 to fennel array for type 'Int' due to error"
)
diff --git a/fennel/expr/visitor.py b/fennel/expr/visitor.py
index b2cf16aa4..052ae63b0 100644
--- a/fennel/expr/visitor.py
+++ b/fennel/expr/visitor.py
@@ -12,6 +12,10 @@
ListHasNull,
ListLen,
ListNoop,
+ ListMap,
+ ListFilter,
+ ListAll,
+ ListAny,
Literal,
MakeStruct,
Ref,
@@ -38,6 +42,9 @@
NumToStr,
Abs,
Floor,
+ Sqrt,
+ Pow,
+ Log,
StringNoop,
StringParse,
StringJsonExtract,
@@ -57,11 +64,14 @@
_DateTime,
DateTimeNoop,
Now,
+ Repeat,
+ Zip,
)
class Visitor(object):
def visit(self, obj):
+ obj = obj.root if hasattr(obj, "root") else obj
if isinstance(obj, Literal):
ret = self.visitLiteral(obj)
@@ -125,6 +135,12 @@ def visit(self, obj):
elif isinstance(obj, Now):
ret = self.visitNow(obj)
+ elif isinstance(obj, Zip):
+ ret = self.visitZip(obj)
+
+ elif isinstance(obj, Repeat):
+ ret = self.visitRepeat(obj)
+
else:
raise InvalidExprException("invalid expression type: %s" % obj)
@@ -151,6 +167,12 @@ def visitIsNull(self, obj):
def visitFillNull(self, obj):
raise NotImplementedError
+ def visitRepeat(self, obj):
+ raise NotImplementedError()
+
+ def visitZip(self, obj):
+ raise NotImplementedError()
+
def visitThen(self, obj):
raise NotImplementedError
@@ -206,7 +228,7 @@ def visitRef(self, obj):
return str(obj)
def visitVar(self, obj):
- return str(obj)
+ return f'var("{obj.var}")'
def visitUnary(self, obj):
return "%s(%s)" % (obj.op, self.visit(obj.operand))
@@ -270,6 +292,14 @@ def visitNumber(self, obj):
return "ABS(%s)" % self.visit(obj.operand)
elif isinstance(obj.op, NumToStr):
return f"TO_STRING({self.visit(obj.operand)})"
+ elif isinstance(obj.op, Sqrt):
+ return f"SQRT({self.visit(obj.operand)})"
+ elif isinstance(obj.op, Pow):
+ return (
+ f"POW({self.visit(obj.operand)}, {self.visit(obj.op.exponent)})"
+ )
+ elif isinstance(obj.op, Log):
+ return f"LOG({self.visit(obj.operand)}, base={obj.op.base})"
else:
raise InvalidExprException("invalid number operation: %s" % obj.op)
@@ -349,6 +379,20 @@ def visitList(self, obj):
return f"LEN({self.visit(obj.expr)})"
elif isinstance(obj.op, ListHasNull):
return f"HAS_NULL({self.visit(obj.expr)})"
+ elif isinstance(obj.op, ListMap):
+ return f'LIST_MAP({self.visit(obj.expr)}, "{obj.op.var}", {self.visit(obj.op.expr)})'
+ elif isinstance(obj.op, ListFilter):
+ return f"LIST_FILTER({self.visit(obj.expr)}, {self.visit(obj.op.func)})"
+ elif isinstance(obj.op, ListAll):
+ return (
+ f"LIST_ALL({self.visit(obj.expr)}, {self.visit(obj.op.func)})"
+ )
+ elif isinstance(obj.op, ListAny):
+ return (
+ f"LIST_ANY({self.visit(obj.expr)}, {self.visit(obj.op.func)})"
+ )
+ else:
+ raise InvalidExprException("invalid list operation: %s" % obj.op)
def visitStruct(self, obj):
if isinstance(obj.op, StructNoop):
@@ -370,6 +414,15 @@ def visitDateTimeLiteral(self, obj):
def visitNow(self, obj):
return "NOW()"
+ def visitZip(self, obj):
+ kwargs = ", ".join(
+ [f"{k}={self.visit(v)}" for k, v in obj.fields.items()]
+ )
+ return f"ZIP({obj.struct_type.__name__}, {kwargs})"
+
+ def visitRepeat(self, obj):
+ return f"REPEAT({self.visit(obj.value)}, {self.visit(obj.by)})"
+
class FetchReferences(Visitor):
@@ -424,6 +477,27 @@ def visitOtherwise(self, obj):
def visitNumber(self, obj):
self.visit(obj.operand)
+ if isinstance(obj.op, Sqrt):
+ pass
+ elif isinstance(obj.op, Pow):
+ self.visit(obj.op.exponent)
+ elif isinstance(obj.op, Log):
+ pass
+ elif isinstance(obj.op, Floor):
+ pass
+ elif isinstance(obj.op, Round):
+ pass
+ elif isinstance(obj.op, Ceil):
+ pass
+ elif isinstance(obj.op, NumToStr):
+ pass
+ elif isinstance(obj.op, Abs):
+ pass
+ elif isinstance(obj.op, MathNoop):
+ pass
+ else:
+ raise InvalidExprException("invalid number operation: %s" % obj.op)
+
def visitString(self, obj):
self.visit(obj.operand)
if isinstance(obj.op, StrContains):
@@ -473,3 +547,11 @@ def visitDateTimeLiteral(self, obj):
def visitNow(self, obj):
pass
+
+ def visitRepeat(self, obj):
+ self.visit(obj.value)
+ self.visit(obj.by)
+
+ def visitZip(self, obj):
+ for k, v in obj.fields.items():
+ self.visit(v)
diff --git a/fennel/gen/expression_pb2.py b/fennel/gen/expression_pb2.py
index ad4239301..2fc06444d 100644
--- a/fennel/gen/expression_pb2.py
+++ b/fennel/gen/expression_pb2.py
@@ -15,7 +15,7 @@
import fennel.gen.schema_pb2 as schema__pb2
-DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x10\x65xpression.proto\x12\x17\x66\x65nnel.proto.expression\x1a\x0cschema.proto\"9\n\x0b\x45valContext\x12\x19\n\x0cnow_col_name\x18\x01 \x01(\tH\x00\x88\x01\x01\x42\x0f\n\r_now_col_name\"\xd4\x07\n\x04\x45xpr\x12+\n\x03ref\x18\x01 \x01(\x0b\x32\x1c.fennel.proto.expression.RefH\x00\x12<\n\x0cjson_literal\x18\x02 \x01(\x0b\x32$.fennel.proto.expression.JsonLiteralH\x00\x12/\n\x05unary\x18\x04 \x01(\x0b\x32\x1e.fennel.proto.expression.UnaryH\x00\x12-\n\x04\x63\x61se\x18\x05 \x01(\x0b\x32\x1d.fennel.proto.expression.CaseH\x00\x12\x31\n\x06\x62inary\x18\x06 \x01(\x0b\x32\x1f.fennel.proto.expression.BinaryH\x00\x12\x31\n\x06isnull\x18\x07 \x01(\x0b\x32\x1f.fennel.proto.expression.IsNullH\x00\x12\x35\n\x08\x66illnull\x18\x08 \x01(\x0b\x32!.fennel.proto.expression.FillNullH\x00\x12\x32\n\x07list_fn\x18\t \x01(\x0b\x32\x1f.fennel.proto.expression.ListFnH\x00\x12\x32\n\x07math_fn\x18\n \x01(\x0b\x32\x1f.fennel.proto.expression.MathFnH\x00\x12\x36\n\tstruct_fn\x18\x0b \x01(\x0b\x32!.fennel.proto.expression.StructFnH\x00\x12\x32\n\x07\x64ict_fn\x18\x0c \x01(\x0b\x32\x1f.fennel.proto.expression.DictFnH\x00\x12\x36\n\tstring_fn\x18\r \x01(\x0b\x32!.fennel.proto.expression.StringFnH\x00\x12:\n\x0b\x64\x61tetime_fn\x18\x0e \x01(\x0b\x32#.fennel.proto.expression.DateTimeFnH\x00\x12\x44\n\x10\x64\x61tetime_literal\x18\x0f \x01(\x0b\x32(.fennel.proto.expression.DatetimeLiteralH\x00\x12:\n\x0bmake_struct\x18\x10 \x01(\x0b\x32#.fennel.proto.expression.MakeStructH\x00\x12\x38\n\nfrom_epoch\x18\x11 \x01(\x0b\x32\".fennel.proto.expression.FromEpochH\x00\x12+\n\x03var\x18\x12 \x01(\x0b\x32\x1c.fennel.proto.expression.VarH\x00\x12+\n\x03now\x18\x13 \x01(\x0b\x32\x1c.fennel.proto.expression.NowH\x00\x42\x06\n\x04node\"\x05\n\x03Now\"\x13\n\x03Var\x12\x0c\n\x04name\x18\x01 \x01(\t\"m\n\tFromEpoch\x12/\n\x08\x64uration\x18\x01 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\x12/\n\x04unit\x18\x02 \x01(\x0e\x32!.fennel.proto.expression.TimeUnit\"\xb3\x01\n\x0f\x44\x61tetimeLiteral\x12\x0c\n\x04year\x18\x01 \x01(\r\x12\r\n\x05month\x18\x02 \x01(\r\x12\x0b\n\x03\x64\x61y\x18\x03 \x01(\r\x12\x0c\n\x04hour\x18\x04 \x01(\r\x12\x0e\n\x06minute\x18\x05 \x01(\r\x12\x0e\n\x06second\x18\x06 \x01(\r\x12\x13\n\x0bmicrosecond\x18\x07 \x01(\r\x12\x33\n\x08timezone\x18\x08 \x01(\x0b\x32!.fennel.proto.expression.Timezone\"\xd1\x01\n\nMakeStruct\x12\x34\n\x0bstruct_type\x18\x01 \x01(\x0b\x32\x1f.fennel.proto.schema.StructType\x12?\n\x06\x66ields\x18\x02 \x03(\x0b\x32/.fennel.proto.expression.MakeStruct.FieldsEntry\x1aL\n\x0b\x46ieldsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12,\n\x05value\x18\x02 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr:\x02\x38\x01\"L\n\x0bJsonLiteral\x12\x0f\n\x07literal\x18\x01 \x01(\t\x12,\n\x05\x64type\x18\x02 \x01(\x0b\x32\x1d.fennel.proto.schema.DataType\"\x13\n\x03Ref\x12\x0c\n\x04name\x18\x01 \x01(\t\"e\n\x05Unary\x12,\n\x02op\x18\x01 \x01(\x0e\x32 .fennel.proto.expression.UnaryOp\x12.\n\x07operand\x18\x02 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\"\x8f\x01\n\x06\x42inary\x12+\n\x04left\x18\x01 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\x12,\n\x05right\x18\x02 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\x12*\n\x02op\x18\x03 \x01(\x0e\x32\x1e.fennel.proto.expression.BinOp\"n\n\x04\x43\x61se\x12\x34\n\twhen_then\x18\x01 \x03(\x0b\x32!.fennel.proto.expression.WhenThen\x12\x30\n\totherwise\x18\x02 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\"d\n\x08WhenThen\x12+\n\x04when\x18\x01 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\x12+\n\x04then\x18\x02 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\"8\n\x06IsNull\x12.\n\x07operand\x18\x01 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\"g\n\x08\x46illNull\x12.\n\x07operand\x18\x01 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\x12+\n\x04\x66ill\x18\x02 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\"\xeb\x04\n\x06ListOp\x12+\n\x03len\x18\x01 \x01(\x0b\x32\x1c.fennel.proto.expression.LenH\x00\x12,\n\x03get\x18\x02 \x01(\x0b\x32\x1d.fennel.proto.expression.ExprH\x00\x12\x35\n\x08\x63ontains\x18\x03 \x01(\x0b\x32!.fennel.proto.expression.ContainsH\x00\x12\x34\n\x08has_null\x18\x04 \x01(\x0b\x32 .fennel.proto.expression.HasNullH\x00\x12/\n\x03sum\x18\x05 \x01(\x0b\x32 .fennel.proto.expression.ListSumH\x00\x12/\n\x03min\x18\x06 \x01(\x0b\x32 .fennel.proto.expression.ListMinH\x00\x12/\n\x03max\x18\x07 \x01(\x0b\x32 .fennel.proto.expression.ListMaxH\x00\x12/\n\x03\x61ll\x18\x08 \x01(\x0b\x32 .fennel.proto.expression.ListAllH\x00\x12/\n\x03\x61ny\x18\t \x01(\x0b\x32 .fennel.proto.expression.ListAnyH\x00\x12\x31\n\x04mean\x18\n \x01(\x0b\x32!.fennel.proto.expression.ListMeanH\x00\x12\x35\n\x06\x66ilter\x18\x0b \x01(\x0b\x32#.fennel.proto.expression.ListFilterH\x00\x12/\n\x03map\x18\x0c \x01(\x0b\x32 .fennel.proto.expression.ListMapH\x00\x42\t\n\x07\x66n_type\"K\n\nListFilter\x12\x0b\n\x03var\x18\x01 \x01(\t\x12\x30\n\tpredicate\x18\x02 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\"G\n\x07ListMap\x12\x0b\n\x03var\x18\x01 \x01(\t\x12/\n\x08map_expr\x18\x02 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\"\t\n\x07ListSum\"\t\n\x07ListMin\"\n\n\x08ListMean\"\t\n\x07ListMax\"\t\n\x07ListAll\"\t\n\x07ListAny\"\x05\n\x03Len\"\t\n\x07HasNull\":\n\x08\x43ontains\x12.\n\x07\x65lement\x18\x01 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\"b\n\x06ListFn\x12+\n\x04list\x18\x01 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\x12+\n\x02\x66n\x18\x02 \x01(\x0b\x32\x1f.fennel.proto.expression.ListOp\"\x89\x02\n\x06MathOp\x12/\n\x05round\x18\x01 \x01(\x0b\x32\x1e.fennel.proto.expression.RoundH\x00\x12+\n\x03\x61\x62s\x18\x02 \x01(\x0b\x32\x1c.fennel.proto.expression.AbsH\x00\x12-\n\x04\x63\x65il\x18\x03 \x01(\x0b\x32\x1d.fennel.proto.expression.CeilH\x00\x12/\n\x05\x66loor\x18\x04 \x01(\x0b\x32\x1e.fennel.proto.expression.FloorH\x00\x12\x36\n\tto_string\x18\x05 \x01(\x0b\x32!.fennel.proto.expression.ToStringH\x00\x42\t\n\x07\x66n_type\"\x1a\n\x05Round\x12\x11\n\tprecision\x18\x01 \x01(\x05\"\x05\n\x03\x41\x62s\"\x06\n\x04\x43\x65il\"\x07\n\x05\x46loor\"\n\n\x08ToString\"e\n\x06MathFn\x12.\n\x07operand\x18\x01 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\x12+\n\x02\x66n\x18\x02 \x01(\x0b\x32\x1f.fennel.proto.expression.MathOp\"&\n\x08StructOp\x12\x0f\n\x05\x66ield\x18\x01 \x01(\tH\x00\x42\t\n\x07\x66n_type\"h\n\x08StructFn\x12-\n\x06struct\x18\x01 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\x12-\n\x02\x66n\x18\x02 \x01(\x0b\x32!.fennel.proto.expression.StructOp\"m\n\x07\x44ictGet\x12,\n\x05\x66ield\x18\x01 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\x12\x34\n\rdefault_value\x18\x03 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\"\xa8\x01\n\x06\x44ictOp\x12+\n\x03len\x18\x01 \x01(\x0b\x32\x1c.fennel.proto.expression.LenH\x00\x12/\n\x03get\x18\x02 \x01(\x0b\x32 .fennel.proto.expression.DictGetH\x00\x12\x35\n\x08\x63ontains\x18\x03 \x01(\x0b\x32!.fennel.proto.expression.ContainsH\x00\x42\t\n\x07\x66n_type\"b\n\x06\x44ictFn\x12+\n\x04\x64ict\x18\x01 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\x12+\n\x02\x66n\x18\x02 \x01(\x0b\x32\x1f.fennel.proto.expression.DictOp\"\x9c\x05\n\x08StringOp\x12+\n\x03len\x18\x01 \x01(\x0b\x32\x1c.fennel.proto.expression.LenH\x00\x12\x33\n\x07tolower\x18\x02 \x01(\x0b\x32 .fennel.proto.expression.ToLowerH\x00\x12\x33\n\x07toupper\x18\x03 \x01(\x0b\x32 .fennel.proto.expression.ToUpperH\x00\x12\x35\n\x08\x63ontains\x18\x04 \x01(\x0b\x32!.fennel.proto.expression.ContainsH\x00\x12\x39\n\nstartswith\x18\x05 \x01(\x0b\x32#.fennel.proto.expression.StartsWithH\x00\x12\x35\n\x08\x65ndswith\x18\x06 \x01(\x0b\x32!.fennel.proto.expression.EndsWithH\x00\x12\x31\n\x06\x63oncat\x18\x07 \x01(\x0b\x32\x1f.fennel.proto.expression.ConcatH\x00\x12\x35\n\x08strptime\x18\x08 \x01(\x0b\x32!.fennel.proto.expression.StrptimeH\x00\x12:\n\x0bjson_decode\x18\t \x01(\x0b\x32#.fennel.proto.expression.JsonDecodeH\x00\x12/\n\x05split\x18\n \x01(\x0b\x32\x1e.fennel.proto.expression.SplitH\x00\x12<\n\x0cjson_extract\x18\x0b \x01(\x0b\x32$.fennel.proto.expression.JsonExtractH\x00\x12\x30\n\x06to_int\x18\x0c \x01(\x0b\x32\x1e.fennel.proto.expression.ToIntH\x00\x42\t\n\x07\x66n_type\"\x1c\n\x08Timezone\x12\x10\n\x08timezone\x18\x01 \x01(\t\":\n\nJsonDecode\x12,\n\x05\x64type\x18\x01 \x01(\x0b\x32\x1d.fennel.proto.schema.DataType\"O\n\x08Strptime\x12\x0e\n\x06\x66ormat\x18\x01 \x01(\t\x12\x33\n\x08timezone\x18\x02 \x01(\x0b\x32!.fennel.proto.expression.Timezone\"\t\n\x07ToLower\"\t\n\x07ToUpper\"8\n\nStartsWith\x12*\n\x03key\x18\x01 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\"6\n\x08\x45ndsWith\x12*\n\x03key\x18\x01 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\"6\n\x06\x43oncat\x12,\n\x05other\x18\x01 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\"h\n\x08StringFn\x12-\n\x06string\x18\x01 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\x12-\n\x02\x66n\x18\x02 \x01(\x0b\x32!.fennel.proto.expression.StringOp\"n\n\nDateTimeFn\x12/\n\x08\x64\x61tetime\x18\x01 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\x12/\n\x02\x66n\x18\x02 \x01(\x0b\x32#.fennel.proto.expression.DateTimeOp\"\xea\x01\n\nDateTimeOp\x12/\n\x05since\x18\x01 \x01(\x0b\x32\x1e.fennel.proto.expression.SinceH\x00\x12:\n\x0bsince_epoch\x18\x02 \x01(\x0b\x32#.fennel.proto.expression.SinceEpochH\x00\x12\x35\n\x08strftime\x18\x03 \x01(\x0b\x32!.fennel.proto.expression.StrftimeH\x00\x12-\n\x04part\x18\x04 \x01(\x0b\x32\x1d.fennel.proto.expression.PartH\x00\x42\t\n\x07\x66n_type\"f\n\x05Since\x12,\n\x05other\x18\x01 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\x12/\n\x04unit\x18\x02 \x01(\x0e\x32!.fennel.proto.expression.TimeUnit\"=\n\nSinceEpoch\x12/\n\x04unit\x18\x01 \x01(\x0e\x32!.fennel.proto.expression.TimeUnit\"O\n\x08Strftime\x12\x0e\n\x06\x66ormat\x18\x01 \x01(\t\x12\x33\n\x08timezone\x18\x02 \x01(\x0b\x32!.fennel.proto.expression.Timezone\"l\n\x04Part\x12/\n\x04unit\x18\x01 \x01(\x0e\x32!.fennel.proto.expression.TimeUnit\x12\x33\n\x08timezone\x18\x02 \x01(\x0b\x32!.fennel.proto.expression.Timezone\"\x14\n\x05Split\x12\x0b\n\x03sep\x18\x01 \x01(\t\"\x1b\n\x0bJsonExtract\x12\x0c\n\x04path\x18\x01 \x01(\t\"\x07\n\x05ToInt*\x1b\n\x07UnaryOp\x12\x07\n\x03NEG\x10\x00\x12\x07\n\x03NOT\x10\x01*\x86\x01\n\x05\x42inOp\x12\x07\n\x03\x41\x44\x44\x10\x00\x12\x07\n\x03SUB\x10\x01\x12\x07\n\x03MUL\x10\x02\x12\x07\n\x03\x44IV\x10\x03\x12\x07\n\x03MOD\x10\x04\x12\r\n\tFLOOR_DIV\x10\x05\x12\x06\n\x02\x45Q\x10\x06\x12\x06\n\x02NE\x10\x07\x12\x06\n\x02GT\x10\x08\x12\x07\n\x03GTE\x10\t\x12\x06\n\x02LT\x10\n\x12\x07\n\x03LTE\x10\x0b\x12\x07\n\x03\x41ND\x10\x0c\x12\x06\n\x02OR\x10\r*\x83\x01\n\x08TimeUnit\x12\x0b\n\x07UNKNOWN\x10\x00\x12\n\n\x06SECOND\x10\x01\x12\n\n\x06MINUTE\x10\x02\x12\x08\n\x04HOUR\x10\x03\x12\x07\n\x03\x44\x41Y\x10\x04\x12\x08\n\x04WEEK\x10\x05\x12\t\n\x05MONTH\x10\x06\x12\x08\n\x04YEAR\x10\x07\x12\x0f\n\x0bMICROSECOND\x10\x08\x12\x0f\n\x0bMILLISECOND\x10\tb\x06proto3')
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x10\x65xpression.proto\x12\x17\x66\x65nnel.proto.expression\x1a\x0cschema.proto\"i\n\x0b\x45valContext\x12\x19\n\x0cnow_col_name\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x1b\n\x0eindex_col_name\x18\x02 \x01(\tH\x01\x88\x01\x01\x42\x0f\n\r_now_col_nameB\x11\n\x0f_index_col_name\"\xb4\x08\n\x04\x45xpr\x12+\n\x03ref\x18\x01 \x01(\x0b\x32\x1c.fennel.proto.expression.RefH\x00\x12<\n\x0cjson_literal\x18\x02 \x01(\x0b\x32$.fennel.proto.expression.JsonLiteralH\x00\x12/\n\x05unary\x18\x04 \x01(\x0b\x32\x1e.fennel.proto.expression.UnaryH\x00\x12-\n\x04\x63\x61se\x18\x05 \x01(\x0b\x32\x1d.fennel.proto.expression.CaseH\x00\x12\x31\n\x06\x62inary\x18\x06 \x01(\x0b\x32\x1f.fennel.proto.expression.BinaryH\x00\x12\x31\n\x06isnull\x18\x07 \x01(\x0b\x32\x1f.fennel.proto.expression.IsNullH\x00\x12\x35\n\x08\x66illnull\x18\x08 \x01(\x0b\x32!.fennel.proto.expression.FillNullH\x00\x12\x32\n\x07list_fn\x18\t \x01(\x0b\x32\x1f.fennel.proto.expression.ListFnH\x00\x12\x32\n\x07math_fn\x18\n \x01(\x0b\x32\x1f.fennel.proto.expression.MathFnH\x00\x12\x36\n\tstruct_fn\x18\x0b \x01(\x0b\x32!.fennel.proto.expression.StructFnH\x00\x12\x32\n\x07\x64ict_fn\x18\x0c \x01(\x0b\x32\x1f.fennel.proto.expression.DictFnH\x00\x12\x36\n\tstring_fn\x18\r \x01(\x0b\x32!.fennel.proto.expression.StringFnH\x00\x12:\n\x0b\x64\x61tetime_fn\x18\x0e \x01(\x0b\x32#.fennel.proto.expression.DateTimeFnH\x00\x12\x44\n\x10\x64\x61tetime_literal\x18\x0f \x01(\x0b\x32(.fennel.proto.expression.DatetimeLiteralH\x00\x12:\n\x0bmake_struct\x18\x10 \x01(\x0b\x32#.fennel.proto.expression.MakeStructH\x00\x12\x38\n\nfrom_epoch\x18\x11 \x01(\x0b\x32\".fennel.proto.expression.FromEpochH\x00\x12+\n\x03var\x18\x12 \x01(\x0b\x32\x1c.fennel.proto.expression.VarH\x00\x12+\n\x03now\x18\x13 \x01(\x0b\x32\x1c.fennel.proto.expression.NowH\x00\x12+\n\x03zip\x18\x14 \x01(\x0b\x32\x1c.fennel.proto.expression.ZipH\x00\x12\x31\n\x06repeat\x18\x15 \x01(\x0b\x32\x1f.fennel.proto.expression.RepeatH\x00\x42\x06\n\x04node\"c\n\x06Repeat\x12+\n\x04\x65xpr\x18\x01 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\x12,\n\x05\x63ount\x18\x02 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\"\x05\n\x03Now\"\x13\n\x03Var\x12\x0c\n\x04name\x18\x01 \x01(\t\"m\n\tFromEpoch\x12/\n\x08\x64uration\x18\x01 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\x12/\n\x04unit\x18\x02 \x01(\x0e\x32!.fennel.proto.expression.TimeUnit\"\xb3\x01\n\x0f\x44\x61tetimeLiteral\x12\x0c\n\x04year\x18\x01 \x01(\r\x12\r\n\x05month\x18\x02 \x01(\r\x12\x0b\n\x03\x64\x61y\x18\x03 \x01(\r\x12\x0c\n\x04hour\x18\x04 \x01(\r\x12\x0e\n\x06minute\x18\x05 \x01(\r\x12\x0e\n\x06second\x18\x06 \x01(\r\x12\x13\n\x0bmicrosecond\x18\x07 \x01(\r\x12\x33\n\x08timezone\x18\x08 \x01(\x0b\x32!.fennel.proto.expression.Timezone\"\xd1\x01\n\nMakeStruct\x12\x34\n\x0bstruct_type\x18\x01 \x01(\x0b\x32\x1f.fennel.proto.schema.StructType\x12?\n\x06\x66ields\x18\x02 \x03(\x0b\x32/.fennel.proto.expression.MakeStruct.FieldsEntry\x1aL\n\x0b\x46ieldsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12,\n\x05value\x18\x02 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr:\x02\x38\x01\"\xc3\x01\n\x03Zip\x12\x34\n\x0bstruct_type\x18\x01 \x01(\x0b\x32\x1f.fennel.proto.schema.StructType\x12\x38\n\x06\x66ields\x18\x02 \x03(\x0b\x32(.fennel.proto.expression.Zip.FieldsEntry\x1aL\n\x0b\x46ieldsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12,\n\x05value\x18\x02 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr:\x02\x38\x01\"L\n\x0bJsonLiteral\x12\x0f\n\x07literal\x18\x01 \x01(\t\x12,\n\x05\x64type\x18\x02 \x01(\x0b\x32\x1d.fennel.proto.schema.DataType\"\x13\n\x03Ref\x12\x0c\n\x04name\x18\x01 \x01(\t\"e\n\x05Unary\x12,\n\x02op\x18\x01 \x01(\x0e\x32 .fennel.proto.expression.UnaryOp\x12.\n\x07operand\x18\x02 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\"\x8f\x01\n\x06\x42inary\x12+\n\x04left\x18\x01 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\x12,\n\x05right\x18\x02 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\x12*\n\x02op\x18\x03 \x01(\x0e\x32\x1e.fennel.proto.expression.BinOp\"n\n\x04\x43\x61se\x12\x34\n\twhen_then\x18\x01 \x03(\x0b\x32!.fennel.proto.expression.WhenThen\x12\x30\n\totherwise\x18\x02 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\"d\n\x08WhenThen\x12+\n\x04when\x18\x01 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\x12+\n\x04then\x18\x02 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\"8\n\x06IsNull\x12.\n\x07operand\x18\x01 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\"g\n\x08\x46illNull\x12.\n\x07operand\x18\x01 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\x12+\n\x04\x66ill\x18\x02 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\"\xeb\x04\n\x06ListOp\x12+\n\x03len\x18\x01 \x01(\x0b\x32\x1c.fennel.proto.expression.LenH\x00\x12,\n\x03get\x18\x02 \x01(\x0b\x32\x1d.fennel.proto.expression.ExprH\x00\x12\x35\n\x08\x63ontains\x18\x03 \x01(\x0b\x32!.fennel.proto.expression.ContainsH\x00\x12\x34\n\x08has_null\x18\x04 \x01(\x0b\x32 .fennel.proto.expression.HasNullH\x00\x12/\n\x03sum\x18\x05 \x01(\x0b\x32 .fennel.proto.expression.ListSumH\x00\x12/\n\x03min\x18\x06 \x01(\x0b\x32 .fennel.proto.expression.ListMinH\x00\x12/\n\x03max\x18\x07 \x01(\x0b\x32 .fennel.proto.expression.ListMaxH\x00\x12/\n\x03\x61ll\x18\x08 \x01(\x0b\x32 .fennel.proto.expression.ListAllH\x00\x12/\n\x03\x61ny\x18\t \x01(\x0b\x32 .fennel.proto.expression.ListAnyH\x00\x12\x31\n\x04mean\x18\n \x01(\x0b\x32!.fennel.proto.expression.ListMeanH\x00\x12\x35\n\x06\x66ilter\x18\x0b \x01(\x0b\x32#.fennel.proto.expression.ListFilterH\x00\x12/\n\x03map\x18\x0c \x01(\x0b\x32 .fennel.proto.expression.ListMapH\x00\x42\t\n\x07\x66n_type\"K\n\nListFilter\x12\x0b\n\x03var\x18\x01 \x01(\t\x12\x30\n\tpredicate\x18\x02 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\"G\n\x07ListMap\x12\x0b\n\x03var\x18\x01 \x01(\t\x12/\n\x08map_expr\x18\x02 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\"\t\n\x07ListSum\"\t\n\x07ListMin\"\n\n\x08ListMean\"\t\n\x07ListMax\"\t\n\x07ListAll\"\t\n\x07ListAny\"\x05\n\x03Len\"\t\n\x07HasNull\":\n\x08\x43ontains\x12.\n\x07\x65lement\x18\x01 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\"b\n\x06ListFn\x12+\n\x04list\x18\x01 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\x12+\n\x02\x66n\x18\x02 \x01(\x0b\x32\x1f.fennel.proto.expression.ListOp\"\x92\x03\n\x06MathOp\x12/\n\x05round\x18\x01 \x01(\x0b\x32\x1e.fennel.proto.expression.RoundH\x00\x12+\n\x03\x61\x62s\x18\x02 \x01(\x0b\x32\x1c.fennel.proto.expression.AbsH\x00\x12-\n\x04\x63\x65il\x18\x03 \x01(\x0b\x32\x1d.fennel.proto.expression.CeilH\x00\x12/\n\x05\x66loor\x18\x04 \x01(\x0b\x32\x1e.fennel.proto.expression.FloorH\x00\x12\x36\n\tto_string\x18\x05 \x01(\x0b\x32!.fennel.proto.expression.ToStringH\x00\x12+\n\x03pow\x18\x06 \x01(\x0b\x32\x1c.fennel.proto.expression.PowH\x00\x12+\n\x03log\x18\x07 \x01(\x0b\x32\x1c.fennel.proto.expression.LogH\x00\x12-\n\x04sqrt\x18\x08 \x01(\x0b\x32\x1d.fennel.proto.expression.SqrtH\x00\x42\t\n\x07\x66n_type\"\x1a\n\x05Round\x12\x11\n\tprecision\x18\x01 \x01(\x05\"6\n\x03Pow\x12/\n\x08\x65xponent\x18\x01 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\"\x13\n\x03Log\x12\x0c\n\x04\x62\x61se\x18\x01 \x01(\x01\"\x06\n\x04Sqrt\"\x05\n\x03\x41\x62s\"\x06\n\x04\x43\x65il\"\x07\n\x05\x46loor\"\n\n\x08ToString\"e\n\x06MathFn\x12.\n\x07operand\x18\x01 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\x12+\n\x02\x66n\x18\x02 \x01(\x0b\x32\x1f.fennel.proto.expression.MathOp\"&\n\x08StructOp\x12\x0f\n\x05\x66ield\x18\x01 \x01(\tH\x00\x42\t\n\x07\x66n_type\"h\n\x08StructFn\x12-\n\x06struct\x18\x01 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\x12-\n\x02\x66n\x18\x02 \x01(\x0b\x32!.fennel.proto.expression.StructOp\"m\n\x07\x44ictGet\x12,\n\x05\x66ield\x18\x01 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\x12\x34\n\rdefault_value\x18\x03 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\"\xa8\x01\n\x06\x44ictOp\x12+\n\x03len\x18\x01 \x01(\x0b\x32\x1c.fennel.proto.expression.LenH\x00\x12/\n\x03get\x18\x02 \x01(\x0b\x32 .fennel.proto.expression.DictGetH\x00\x12\x35\n\x08\x63ontains\x18\x03 \x01(\x0b\x32!.fennel.proto.expression.ContainsH\x00\x42\t\n\x07\x66n_type\"b\n\x06\x44ictFn\x12+\n\x04\x64ict\x18\x01 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\x12+\n\x02\x66n\x18\x02 \x01(\x0b\x32\x1f.fennel.proto.expression.DictOp\"\x9c\x05\n\x08StringOp\x12+\n\x03len\x18\x01 \x01(\x0b\x32\x1c.fennel.proto.expression.LenH\x00\x12\x33\n\x07tolower\x18\x02 \x01(\x0b\x32 .fennel.proto.expression.ToLowerH\x00\x12\x33\n\x07toupper\x18\x03 \x01(\x0b\x32 .fennel.proto.expression.ToUpperH\x00\x12\x35\n\x08\x63ontains\x18\x04 \x01(\x0b\x32!.fennel.proto.expression.ContainsH\x00\x12\x39\n\nstartswith\x18\x05 \x01(\x0b\x32#.fennel.proto.expression.StartsWithH\x00\x12\x35\n\x08\x65ndswith\x18\x06 \x01(\x0b\x32!.fennel.proto.expression.EndsWithH\x00\x12\x31\n\x06\x63oncat\x18\x07 \x01(\x0b\x32\x1f.fennel.proto.expression.ConcatH\x00\x12\x35\n\x08strptime\x18\x08 \x01(\x0b\x32!.fennel.proto.expression.StrptimeH\x00\x12:\n\x0bjson_decode\x18\t \x01(\x0b\x32#.fennel.proto.expression.JsonDecodeH\x00\x12/\n\x05split\x18\n \x01(\x0b\x32\x1e.fennel.proto.expression.SplitH\x00\x12<\n\x0cjson_extract\x18\x0b \x01(\x0b\x32$.fennel.proto.expression.JsonExtractH\x00\x12\x30\n\x06to_int\x18\x0c \x01(\x0b\x32\x1e.fennel.proto.expression.ToIntH\x00\x42\t\n\x07\x66n_type\"\x1c\n\x08Timezone\x12\x10\n\x08timezone\x18\x01 \x01(\t\":\n\nJsonDecode\x12,\n\x05\x64type\x18\x01 \x01(\x0b\x32\x1d.fennel.proto.schema.DataType\"O\n\x08Strptime\x12\x0e\n\x06\x66ormat\x18\x01 \x01(\t\x12\x33\n\x08timezone\x18\x02 \x01(\x0b\x32!.fennel.proto.expression.Timezone\"\t\n\x07ToLower\"\t\n\x07ToUpper\"8\n\nStartsWith\x12*\n\x03key\x18\x01 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\"6\n\x08\x45ndsWith\x12*\n\x03key\x18\x01 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\"6\n\x06\x43oncat\x12,\n\x05other\x18\x01 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\"h\n\x08StringFn\x12-\n\x06string\x18\x01 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\x12-\n\x02\x66n\x18\x02 \x01(\x0b\x32!.fennel.proto.expression.StringOp\"n\n\nDateTimeFn\x12/\n\x08\x64\x61tetime\x18\x01 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\x12/\n\x02\x66n\x18\x02 \x01(\x0b\x32#.fennel.proto.expression.DateTimeOp\"\xea\x01\n\nDateTimeOp\x12/\n\x05since\x18\x01 \x01(\x0b\x32\x1e.fennel.proto.expression.SinceH\x00\x12:\n\x0bsince_epoch\x18\x02 \x01(\x0b\x32#.fennel.proto.expression.SinceEpochH\x00\x12\x35\n\x08strftime\x18\x03 \x01(\x0b\x32!.fennel.proto.expression.StrftimeH\x00\x12-\n\x04part\x18\x04 \x01(\x0b\x32\x1d.fennel.proto.expression.PartH\x00\x42\t\n\x07\x66n_type\"f\n\x05Since\x12,\n\x05other\x18\x01 \x01(\x0b\x32\x1d.fennel.proto.expression.Expr\x12/\n\x04unit\x18\x02 \x01(\x0e\x32!.fennel.proto.expression.TimeUnit\"=\n\nSinceEpoch\x12/\n\x04unit\x18\x01 \x01(\x0e\x32!.fennel.proto.expression.TimeUnit\"O\n\x08Strftime\x12\x0e\n\x06\x66ormat\x18\x01 \x01(\t\x12\x33\n\x08timezone\x18\x02 \x01(\x0b\x32!.fennel.proto.expression.Timezone\"l\n\x04Part\x12/\n\x04unit\x18\x01 \x01(\x0e\x32!.fennel.proto.expression.TimeUnit\x12\x33\n\x08timezone\x18\x02 \x01(\x0b\x32!.fennel.proto.expression.Timezone\"\x14\n\x05Split\x12\x0b\n\x03sep\x18\x01 \x01(\t\"\x1b\n\x0bJsonExtract\x12\x0c\n\x04path\x18\x01 \x01(\t\"\x07\n\x05ToInt*\x1b\n\x07UnaryOp\x12\x07\n\x03NEG\x10\x00\x12\x07\n\x03NOT\x10\x01*\x86\x01\n\x05\x42inOp\x12\x07\n\x03\x41\x44\x44\x10\x00\x12\x07\n\x03SUB\x10\x01\x12\x07\n\x03MUL\x10\x02\x12\x07\n\x03\x44IV\x10\x03\x12\x07\n\x03MOD\x10\x04\x12\r\n\tFLOOR_DIV\x10\x05\x12\x06\n\x02\x45Q\x10\x06\x12\x06\n\x02NE\x10\x07\x12\x06\n\x02GT\x10\x08\x12\x07\n\x03GTE\x10\t\x12\x06\n\x02LT\x10\n\x12\x07\n\x03LTE\x10\x0b\x12\x07\n\x03\x41ND\x10\x0c\x12\x06\n\x02OR\x10\r*\x83\x01\n\x08TimeUnit\x12\x0b\n\x07UNKNOWN\x10\x00\x12\n\n\x06SECOND\x10\x01\x12\n\n\x06MINUTE\x10\x02\x12\x08\n\x04HOUR\x10\x03\x12\x07\n\x03\x44\x41Y\x10\x04\x12\x08\n\x04WEEK\x10\x05\x12\t\n\x05MONTH\x10\x06\x12\x08\n\x04YEAR\x10\x07\x12\x0f\n\x0bMICROSECOND\x10\x08\x12\x0f\n\x0bMILLISECOND\x10\tb\x06proto3')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
@@ -24,130 +24,144 @@
DESCRIPTOR._loaded_options = None
_globals['_MAKESTRUCT_FIELDSENTRY']._loaded_options = None
_globals['_MAKESTRUCT_FIELDSENTRY']._serialized_options = b'8\001'
- _globals['_UNARYOP']._serialized_start=6246
- _globals['_UNARYOP']._serialized_end=6273
- _globals['_BINOP']._serialized_start=6276
- _globals['_BINOP']._serialized_end=6410
- _globals['_TIMEUNIT']._serialized_start=6413
- _globals['_TIMEUNIT']._serialized_end=6544
+ _globals['_ZIP_FIELDSENTRY']._loaded_options = None
+ _globals['_ZIP_FIELDSENTRY']._serialized_options = b'8\001'
+ _globals['_UNARYOP']._serialized_start=6911
+ _globals['_UNARYOP']._serialized_end=6938
+ _globals['_BINOP']._serialized_start=6941
+ _globals['_BINOP']._serialized_end=7075
+ _globals['_TIMEUNIT']._serialized_start=7078
+ _globals['_TIMEUNIT']._serialized_end=7209
_globals['_EVALCONTEXT']._serialized_start=59
- _globals['_EVALCONTEXT']._serialized_end=116
- _globals['_EXPR']._serialized_start=119
- _globals['_EXPR']._serialized_end=1099
- _globals['_NOW']._serialized_start=1101
- _globals['_NOW']._serialized_end=1106
- _globals['_VAR']._serialized_start=1108
- _globals['_VAR']._serialized_end=1127
- _globals['_FROMEPOCH']._serialized_start=1129
- _globals['_FROMEPOCH']._serialized_end=1238
- _globals['_DATETIMELITERAL']._serialized_start=1241
- _globals['_DATETIMELITERAL']._serialized_end=1420
- _globals['_MAKESTRUCT']._serialized_start=1423
- _globals['_MAKESTRUCT']._serialized_end=1632
- _globals['_MAKESTRUCT_FIELDSENTRY']._serialized_start=1556
- _globals['_MAKESTRUCT_FIELDSENTRY']._serialized_end=1632
- _globals['_JSONLITERAL']._serialized_start=1634
- _globals['_JSONLITERAL']._serialized_end=1710
- _globals['_REF']._serialized_start=1712
- _globals['_REF']._serialized_end=1731
- _globals['_UNARY']._serialized_start=1733
- _globals['_UNARY']._serialized_end=1834
- _globals['_BINARY']._serialized_start=1837
- _globals['_BINARY']._serialized_end=1980
- _globals['_CASE']._serialized_start=1982
- _globals['_CASE']._serialized_end=2092
- _globals['_WHENTHEN']._serialized_start=2094
- _globals['_WHENTHEN']._serialized_end=2194
- _globals['_ISNULL']._serialized_start=2196
- _globals['_ISNULL']._serialized_end=2252
- _globals['_FILLNULL']._serialized_start=2254
- _globals['_FILLNULL']._serialized_end=2357
- _globals['_LISTOP']._serialized_start=2360
- _globals['_LISTOP']._serialized_end=2979
- _globals['_LISTFILTER']._serialized_start=2981
- _globals['_LISTFILTER']._serialized_end=3056
- _globals['_LISTMAP']._serialized_start=3058
- _globals['_LISTMAP']._serialized_end=3129
- _globals['_LISTSUM']._serialized_start=3131
- _globals['_LISTSUM']._serialized_end=3140
- _globals['_LISTMIN']._serialized_start=3142
- _globals['_LISTMIN']._serialized_end=3151
- _globals['_LISTMEAN']._serialized_start=3153
- _globals['_LISTMEAN']._serialized_end=3163
- _globals['_LISTMAX']._serialized_start=3165
- _globals['_LISTMAX']._serialized_end=3174
- _globals['_LISTALL']._serialized_start=3176
- _globals['_LISTALL']._serialized_end=3185
- _globals['_LISTANY']._serialized_start=3187
- _globals['_LISTANY']._serialized_end=3196
- _globals['_LEN']._serialized_start=3198
- _globals['_LEN']._serialized_end=3203
- _globals['_HASNULL']._serialized_start=3205
- _globals['_HASNULL']._serialized_end=3214
- _globals['_CONTAINS']._serialized_start=3216
- _globals['_CONTAINS']._serialized_end=3274
- _globals['_LISTFN']._serialized_start=3276
- _globals['_LISTFN']._serialized_end=3374
- _globals['_MATHOP']._serialized_start=3377
- _globals['_MATHOP']._serialized_end=3642
- _globals['_ROUND']._serialized_start=3644
- _globals['_ROUND']._serialized_end=3670
- _globals['_ABS']._serialized_start=3672
- _globals['_ABS']._serialized_end=3677
- _globals['_CEIL']._serialized_start=3679
- _globals['_CEIL']._serialized_end=3685
- _globals['_FLOOR']._serialized_start=3687
- _globals['_FLOOR']._serialized_end=3694
- _globals['_TOSTRING']._serialized_start=3696
- _globals['_TOSTRING']._serialized_end=3706
- _globals['_MATHFN']._serialized_start=3708
- _globals['_MATHFN']._serialized_end=3809
- _globals['_STRUCTOP']._serialized_start=3811
- _globals['_STRUCTOP']._serialized_end=3849
- _globals['_STRUCTFN']._serialized_start=3851
- _globals['_STRUCTFN']._serialized_end=3955
- _globals['_DICTGET']._serialized_start=3957
- _globals['_DICTGET']._serialized_end=4066
- _globals['_DICTOP']._serialized_start=4069
- _globals['_DICTOP']._serialized_end=4237
- _globals['_DICTFN']._serialized_start=4239
- _globals['_DICTFN']._serialized_end=4337
- _globals['_STRINGOP']._serialized_start=4340
- _globals['_STRINGOP']._serialized_end=5008
- _globals['_TIMEZONE']._serialized_start=5010
- _globals['_TIMEZONE']._serialized_end=5038
- _globals['_JSONDECODE']._serialized_start=5040
- _globals['_JSONDECODE']._serialized_end=5098
- _globals['_STRPTIME']._serialized_start=5100
- _globals['_STRPTIME']._serialized_end=5179
- _globals['_TOLOWER']._serialized_start=5181
- _globals['_TOLOWER']._serialized_end=5190
- _globals['_TOUPPER']._serialized_start=5192
- _globals['_TOUPPER']._serialized_end=5201
- _globals['_STARTSWITH']._serialized_start=5203
- _globals['_STARTSWITH']._serialized_end=5259
- _globals['_ENDSWITH']._serialized_start=5261
- _globals['_ENDSWITH']._serialized_end=5315
- _globals['_CONCAT']._serialized_start=5317
- _globals['_CONCAT']._serialized_end=5371
- _globals['_STRINGFN']._serialized_start=5373
- _globals['_STRINGFN']._serialized_end=5477
- _globals['_DATETIMEFN']._serialized_start=5479
- _globals['_DATETIMEFN']._serialized_end=5589
- _globals['_DATETIMEOP']._serialized_start=5592
- _globals['_DATETIMEOP']._serialized_end=5826
- _globals['_SINCE']._serialized_start=5828
- _globals['_SINCE']._serialized_end=5930
- _globals['_SINCEEPOCH']._serialized_start=5932
- _globals['_SINCEEPOCH']._serialized_end=5993
- _globals['_STRFTIME']._serialized_start=5995
- _globals['_STRFTIME']._serialized_end=6074
- _globals['_PART']._serialized_start=6076
- _globals['_PART']._serialized_end=6184
- _globals['_SPLIT']._serialized_start=6186
- _globals['_SPLIT']._serialized_end=6206
- _globals['_JSONEXTRACT']._serialized_start=6208
- _globals['_JSONEXTRACT']._serialized_end=6235
- _globals['_TOINT']._serialized_start=6237
- _globals['_TOINT']._serialized_end=6244
+ _globals['_EVALCONTEXT']._serialized_end=164
+ _globals['_EXPR']._serialized_start=167
+ _globals['_EXPR']._serialized_end=1243
+ _globals['_REPEAT']._serialized_start=1245
+ _globals['_REPEAT']._serialized_end=1344
+ _globals['_NOW']._serialized_start=1346
+ _globals['_NOW']._serialized_end=1351
+ _globals['_VAR']._serialized_start=1353
+ _globals['_VAR']._serialized_end=1372
+ _globals['_FROMEPOCH']._serialized_start=1374
+ _globals['_FROMEPOCH']._serialized_end=1483
+ _globals['_DATETIMELITERAL']._serialized_start=1486
+ _globals['_DATETIMELITERAL']._serialized_end=1665
+ _globals['_MAKESTRUCT']._serialized_start=1668
+ _globals['_MAKESTRUCT']._serialized_end=1877
+ _globals['_MAKESTRUCT_FIELDSENTRY']._serialized_start=1801
+ _globals['_MAKESTRUCT_FIELDSENTRY']._serialized_end=1877
+ _globals['_ZIP']._serialized_start=1880
+ _globals['_ZIP']._serialized_end=2075
+ _globals['_ZIP_FIELDSENTRY']._serialized_start=1801
+ _globals['_ZIP_FIELDSENTRY']._serialized_end=1877
+ _globals['_JSONLITERAL']._serialized_start=2077
+ _globals['_JSONLITERAL']._serialized_end=2153
+ _globals['_REF']._serialized_start=2155
+ _globals['_REF']._serialized_end=2174
+ _globals['_UNARY']._serialized_start=2176
+ _globals['_UNARY']._serialized_end=2277
+ _globals['_BINARY']._serialized_start=2280
+ _globals['_BINARY']._serialized_end=2423
+ _globals['_CASE']._serialized_start=2425
+ _globals['_CASE']._serialized_end=2535
+ _globals['_WHENTHEN']._serialized_start=2537
+ _globals['_WHENTHEN']._serialized_end=2637
+ _globals['_ISNULL']._serialized_start=2639
+ _globals['_ISNULL']._serialized_end=2695
+ _globals['_FILLNULL']._serialized_start=2697
+ _globals['_FILLNULL']._serialized_end=2800
+ _globals['_LISTOP']._serialized_start=2803
+ _globals['_LISTOP']._serialized_end=3422
+ _globals['_LISTFILTER']._serialized_start=3424
+ _globals['_LISTFILTER']._serialized_end=3499
+ _globals['_LISTMAP']._serialized_start=3501
+ _globals['_LISTMAP']._serialized_end=3572
+ _globals['_LISTSUM']._serialized_start=3574
+ _globals['_LISTSUM']._serialized_end=3583
+ _globals['_LISTMIN']._serialized_start=3585
+ _globals['_LISTMIN']._serialized_end=3594
+ _globals['_LISTMEAN']._serialized_start=3596
+ _globals['_LISTMEAN']._serialized_end=3606
+ _globals['_LISTMAX']._serialized_start=3608
+ _globals['_LISTMAX']._serialized_end=3617
+ _globals['_LISTALL']._serialized_start=3619
+ _globals['_LISTALL']._serialized_end=3628
+ _globals['_LISTANY']._serialized_start=3630
+ _globals['_LISTANY']._serialized_end=3639
+ _globals['_LEN']._serialized_start=3641
+ _globals['_LEN']._serialized_end=3646
+ _globals['_HASNULL']._serialized_start=3648
+ _globals['_HASNULL']._serialized_end=3657
+ _globals['_CONTAINS']._serialized_start=3659
+ _globals['_CONTAINS']._serialized_end=3717
+ _globals['_LISTFN']._serialized_start=3719
+ _globals['_LISTFN']._serialized_end=3817
+ _globals['_MATHOP']._serialized_start=3820
+ _globals['_MATHOP']._serialized_end=4222
+ _globals['_ROUND']._serialized_start=4224
+ _globals['_ROUND']._serialized_end=4250
+ _globals['_POW']._serialized_start=4252
+ _globals['_POW']._serialized_end=4306
+ _globals['_LOG']._serialized_start=4308
+ _globals['_LOG']._serialized_end=4327
+ _globals['_SQRT']._serialized_start=4329
+ _globals['_SQRT']._serialized_end=4335
+ _globals['_ABS']._serialized_start=4337
+ _globals['_ABS']._serialized_end=4342
+ _globals['_CEIL']._serialized_start=4344
+ _globals['_CEIL']._serialized_end=4350
+ _globals['_FLOOR']._serialized_start=4352
+ _globals['_FLOOR']._serialized_end=4359
+ _globals['_TOSTRING']._serialized_start=4361
+ _globals['_TOSTRING']._serialized_end=4371
+ _globals['_MATHFN']._serialized_start=4373
+ _globals['_MATHFN']._serialized_end=4474
+ _globals['_STRUCTOP']._serialized_start=4476
+ _globals['_STRUCTOP']._serialized_end=4514
+ _globals['_STRUCTFN']._serialized_start=4516
+ _globals['_STRUCTFN']._serialized_end=4620
+ _globals['_DICTGET']._serialized_start=4622
+ _globals['_DICTGET']._serialized_end=4731
+ _globals['_DICTOP']._serialized_start=4734
+ _globals['_DICTOP']._serialized_end=4902
+ _globals['_DICTFN']._serialized_start=4904
+ _globals['_DICTFN']._serialized_end=5002
+ _globals['_STRINGOP']._serialized_start=5005
+ _globals['_STRINGOP']._serialized_end=5673
+ _globals['_TIMEZONE']._serialized_start=5675
+ _globals['_TIMEZONE']._serialized_end=5703
+ _globals['_JSONDECODE']._serialized_start=5705
+ _globals['_JSONDECODE']._serialized_end=5763
+ _globals['_STRPTIME']._serialized_start=5765
+ _globals['_STRPTIME']._serialized_end=5844
+ _globals['_TOLOWER']._serialized_start=5846
+ _globals['_TOLOWER']._serialized_end=5855
+ _globals['_TOUPPER']._serialized_start=5857
+ _globals['_TOUPPER']._serialized_end=5866
+ _globals['_STARTSWITH']._serialized_start=5868
+ _globals['_STARTSWITH']._serialized_end=5924
+ _globals['_ENDSWITH']._serialized_start=5926
+ _globals['_ENDSWITH']._serialized_end=5980
+ _globals['_CONCAT']._serialized_start=5982
+ _globals['_CONCAT']._serialized_end=6036
+ _globals['_STRINGFN']._serialized_start=6038
+ _globals['_STRINGFN']._serialized_end=6142
+ _globals['_DATETIMEFN']._serialized_start=6144
+ _globals['_DATETIMEFN']._serialized_end=6254
+ _globals['_DATETIMEOP']._serialized_start=6257
+ _globals['_DATETIMEOP']._serialized_end=6491
+ _globals['_SINCE']._serialized_start=6493
+ _globals['_SINCE']._serialized_end=6595
+ _globals['_SINCEEPOCH']._serialized_start=6597
+ _globals['_SINCEEPOCH']._serialized_end=6658
+ _globals['_STRFTIME']._serialized_start=6660
+ _globals['_STRFTIME']._serialized_end=6739
+ _globals['_PART']._serialized_start=6741
+ _globals['_PART']._serialized_end=6849
+ _globals['_SPLIT']._serialized_start=6851
+ _globals['_SPLIT']._serialized_end=6871
+ _globals['_JSONEXTRACT']._serialized_start=6873
+ _globals['_JSONEXTRACT']._serialized_end=6900
+ _globals['_TOINT']._serialized_start=6902
+ _globals['_TOINT']._serialized_end=6909
# @@protoc_insertion_point(module_scope)
diff --git a/fennel/gen/expression_pb2.pyi b/fennel/gen/expression_pb2.pyi
index e00682622..66da138fc 100644
--- a/fennel/gen/expression_pb2.pyi
+++ b/fennel/gen/expression_pb2.pyi
@@ -115,14 +115,20 @@ class EvalContext(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
NOW_COL_NAME_FIELD_NUMBER: builtins.int
+ INDEX_COL_NAME_FIELD_NUMBER: builtins.int
now_col_name: builtins.str
+ index_col_name: builtins.str
def __init__(
self,
*,
now_col_name: builtins.str | None = ...,
+ index_col_name: builtins.str | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["_now_col_name", b"_now_col_name", "now_col_name", b"now_col_name"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["_now_col_name", b"_now_col_name", "now_col_name", b"now_col_name"]) -> None: ...
+ def HasField(self, field_name: typing_extensions.Literal["_index_col_name", b"_index_col_name", "_now_col_name", b"_now_col_name", "index_col_name", b"index_col_name", "now_col_name", b"now_col_name"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing_extensions.Literal["_index_col_name", b"_index_col_name", "_now_col_name", b"_now_col_name", "index_col_name", b"index_col_name", "now_col_name", b"now_col_name"]) -> None: ...
+ @typing.overload
+ def WhichOneof(self, oneof_group: typing_extensions.Literal["_index_col_name", b"_index_col_name"]) -> typing_extensions.Literal["index_col_name"] | None: ...
+ @typing.overload
def WhichOneof(self, oneof_group: typing_extensions.Literal["_now_col_name", b"_now_col_name"]) -> typing_extensions.Literal["now_col_name"] | None: ...
global___EvalContext = EvalContext
@@ -149,6 +155,8 @@ class Expr(google.protobuf.message.Message):
FROM_EPOCH_FIELD_NUMBER: builtins.int
VAR_FIELD_NUMBER: builtins.int
NOW_FIELD_NUMBER: builtins.int
+ ZIP_FIELD_NUMBER: builtins.int
+ REPEAT_FIELD_NUMBER: builtins.int
@property
def ref(self) -> global___Ref: ...
@property
@@ -186,6 +194,10 @@ class Expr(google.protobuf.message.Message):
def var(self) -> global___Var: ...
@property
def now(self) -> global___Now: ...
+ @property
+ def zip(self) -> global___Zip: ...
+ @property
+ def repeat(self) -> global___Repeat: ...
def __init__(
self,
*,
@@ -207,13 +219,36 @@ class Expr(google.protobuf.message.Message):
from_epoch: global___FromEpoch | None = ...,
var: global___Var | None = ...,
now: global___Now | None = ...,
+ zip: global___Zip | None = ...,
+ repeat: global___Repeat | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["binary", b"binary", "case", b"case", "datetime_fn", b"datetime_fn", "datetime_literal", b"datetime_literal", "dict_fn", b"dict_fn", "fillnull", b"fillnull", "from_epoch", b"from_epoch", "isnull", b"isnull", "json_literal", b"json_literal", "list_fn", b"list_fn", "make_struct", b"make_struct", "math_fn", b"math_fn", "node", b"node", "now", b"now", "ref", b"ref", "string_fn", b"string_fn", "struct_fn", b"struct_fn", "unary", b"unary", "var", b"var"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["binary", b"binary", "case", b"case", "datetime_fn", b"datetime_fn", "datetime_literal", b"datetime_literal", "dict_fn", b"dict_fn", "fillnull", b"fillnull", "from_epoch", b"from_epoch", "isnull", b"isnull", "json_literal", b"json_literal", "list_fn", b"list_fn", "make_struct", b"make_struct", "math_fn", b"math_fn", "node", b"node", "now", b"now", "ref", b"ref", "string_fn", b"string_fn", "struct_fn", b"struct_fn", "unary", b"unary", "var", b"var"]) -> None: ...
- def WhichOneof(self, oneof_group: typing_extensions.Literal["node", b"node"]) -> typing_extensions.Literal["ref", "json_literal", "unary", "case", "binary", "isnull", "fillnull", "list_fn", "math_fn", "struct_fn", "dict_fn", "string_fn", "datetime_fn", "datetime_literal", "make_struct", "from_epoch", "var", "now"] | None: ...
+ def HasField(self, field_name: typing_extensions.Literal["binary", b"binary", "case", b"case", "datetime_fn", b"datetime_fn", "datetime_literal", b"datetime_literal", "dict_fn", b"dict_fn", "fillnull", b"fillnull", "from_epoch", b"from_epoch", "isnull", b"isnull", "json_literal", b"json_literal", "list_fn", b"list_fn", "make_struct", b"make_struct", "math_fn", b"math_fn", "node", b"node", "now", b"now", "ref", b"ref", "repeat", b"repeat", "string_fn", b"string_fn", "struct_fn", b"struct_fn", "unary", b"unary", "var", b"var", "zip", b"zip"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing_extensions.Literal["binary", b"binary", "case", b"case", "datetime_fn", b"datetime_fn", "datetime_literal", b"datetime_literal", "dict_fn", b"dict_fn", "fillnull", b"fillnull", "from_epoch", b"from_epoch", "isnull", b"isnull", "json_literal", b"json_literal", "list_fn", b"list_fn", "make_struct", b"make_struct", "math_fn", b"math_fn", "node", b"node", "now", b"now", "ref", b"ref", "repeat", b"repeat", "string_fn", b"string_fn", "struct_fn", b"struct_fn", "unary", b"unary", "var", b"var", "zip", b"zip"]) -> None: ...
+ def WhichOneof(self, oneof_group: typing_extensions.Literal["node", b"node"]) -> typing_extensions.Literal["ref", "json_literal", "unary", "case", "binary", "isnull", "fillnull", "list_fn", "math_fn", "struct_fn", "dict_fn", "string_fn", "datetime_fn", "datetime_literal", "make_struct", "from_epoch", "var", "now", "zip", "repeat"] | None: ...
global___Expr = Expr
+@typing_extensions.final
+class Repeat(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ EXPR_FIELD_NUMBER: builtins.int
+ COUNT_FIELD_NUMBER: builtins.int
+ @property
+ def expr(self) -> global___Expr: ...
+ @property
+ def count(self) -> global___Expr: ...
+ def __init__(
+ self,
+ *,
+ expr: global___Expr | None = ...,
+ count: global___Expr | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing_extensions.Literal["count", b"count", "expr", b"expr"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing_extensions.Literal["count", b"count", "expr", b"expr"]) -> None: ...
+
+global___Repeat = Repeat
+
@typing_extensions.final
class Now(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -336,6 +371,45 @@ class MakeStruct(google.protobuf.message.Message):
global___MakeStruct = MakeStruct
+@typing_extensions.final
+class Zip(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ @typing_extensions.final
+ class FieldsEntry(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ KEY_FIELD_NUMBER: builtins.int
+ VALUE_FIELD_NUMBER: builtins.int
+ key: builtins.str
+ @property
+ def value(self) -> global___Expr: ...
+ def __init__(
+ self,
+ *,
+ key: builtins.str = ...,
+ value: global___Expr | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing_extensions.Literal["value", b"value"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing_extensions.Literal["key", b"key", "value", b"value"]) -> None: ...
+
+ STRUCT_TYPE_FIELD_NUMBER: builtins.int
+ FIELDS_FIELD_NUMBER: builtins.int
+ @property
+ def struct_type(self) -> schema_pb2.StructType: ...
+ @property
+ def fields(self) -> google.protobuf.internal.containers.MessageMap[builtins.str, global___Expr]: ...
+ def __init__(
+ self,
+ *,
+ struct_type: schema_pb2.StructType | None = ...,
+ fields: collections.abc.Mapping[builtins.str, global___Expr] | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing_extensions.Literal["struct_type", b"struct_type"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing_extensions.Literal["fields", b"fields", "struct_type", b"struct_type"]) -> None: ...
+
+global___Zip = Zip
+
@typing_extensions.final
class JsonLiteral(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@@ -727,6 +801,9 @@ class MathOp(google.protobuf.message.Message):
CEIL_FIELD_NUMBER: builtins.int
FLOOR_FIELD_NUMBER: builtins.int
TO_STRING_FIELD_NUMBER: builtins.int
+ POW_FIELD_NUMBER: builtins.int
+ LOG_FIELD_NUMBER: builtins.int
+ SQRT_FIELD_NUMBER: builtins.int
@property
def round(self) -> global___Round: ...
@property
@@ -737,6 +814,12 @@ class MathOp(google.protobuf.message.Message):
def floor(self) -> global___Floor: ...
@property
def to_string(self) -> global___ToString: ...
+ @property
+ def pow(self) -> global___Pow: ...
+ @property
+ def log(self) -> global___Log: ...
+ @property
+ def sqrt(self) -> global___Sqrt: ...
def __init__(
self,
*,
@@ -745,10 +828,13 @@ class MathOp(google.protobuf.message.Message):
ceil: global___Ceil | None = ...,
floor: global___Floor | None = ...,
to_string: global___ToString | None = ...,
+ pow: global___Pow | None = ...,
+ log: global___Log | None = ...,
+ sqrt: global___Sqrt | None = ...,
) -> None: ...
- def HasField(self, field_name: typing_extensions.Literal["abs", b"abs", "ceil", b"ceil", "floor", b"floor", "fn_type", b"fn_type", "round", b"round", "to_string", b"to_string"]) -> builtins.bool: ...
- def ClearField(self, field_name: typing_extensions.Literal["abs", b"abs", "ceil", b"ceil", "floor", b"floor", "fn_type", b"fn_type", "round", b"round", "to_string", b"to_string"]) -> None: ...
- def WhichOneof(self, oneof_group: typing_extensions.Literal["fn_type", b"fn_type"]) -> typing_extensions.Literal["round", "abs", "ceil", "floor", "to_string"] | None: ...
+ def HasField(self, field_name: typing_extensions.Literal["abs", b"abs", "ceil", b"ceil", "floor", b"floor", "fn_type", b"fn_type", "log", b"log", "pow", b"pow", "round", b"round", "sqrt", b"sqrt", "to_string", b"to_string"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing_extensions.Literal["abs", b"abs", "ceil", b"ceil", "floor", b"floor", "fn_type", b"fn_type", "log", b"log", "pow", b"pow", "round", b"round", "sqrt", b"sqrt", "to_string", b"to_string"]) -> None: ...
+ def WhichOneof(self, oneof_group: typing_extensions.Literal["fn_type", b"fn_type"]) -> typing_extensions.Literal["round", "abs", "ceil", "floor", "to_string", "pow", "log", "sqrt"] | None: ...
global___MathOp = MathOp
@@ -767,6 +853,48 @@ class Round(google.protobuf.message.Message):
global___Round = Round
+@typing_extensions.final
+class Pow(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ EXPONENT_FIELD_NUMBER: builtins.int
+ @property
+ def exponent(self) -> global___Expr: ...
+ def __init__(
+ self,
+ *,
+ exponent: global___Expr | None = ...,
+ ) -> None: ...
+ def HasField(self, field_name: typing_extensions.Literal["exponent", b"exponent"]) -> builtins.bool: ...
+ def ClearField(self, field_name: typing_extensions.Literal["exponent", b"exponent"]) -> None: ...
+
+global___Pow = Pow
+
+@typing_extensions.final
+class Log(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ BASE_FIELD_NUMBER: builtins.int
+ base: builtins.float
+ def __init__(
+ self,
+ *,
+ base: builtins.float = ...,
+ ) -> None: ...
+ def ClearField(self, field_name: typing_extensions.Literal["base", b"base"]) -> None: ...
+
+global___Log = Log
+
+@typing_extensions.final
+class Sqrt(google.protobuf.message.Message):
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+ def __init__(
+ self,
+ ) -> None: ...
+
+global___Sqrt = Sqrt
+
@typing_extensions.final
class Abs(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
diff --git a/fennel/internal_lib/schema/schema.py b/fennel/internal_lib/schema/schema.py
index 21ae8c48b..d62b72426 100644
--- a/fennel/internal_lib/schema/schema.py
+++ b/fennel/internal_lib/schema/schema.py
@@ -241,6 +241,8 @@ def get_datatype(type_: Any) -> schema_proto.DataType:
fields=fields, name=type_.__name__
)
)
+ elif type_ is None:
+ return schema_proto.DataType(null_type=schema_proto.NullType())
raise ValueError(f"Cannot serialize type {type_}.")
diff --git a/poetry.lock b/poetry.lock
index ed5356788..e380a5ab6 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -779,48 +779,48 @@ devel = ["colorama", "json-spec", "jsonschema", "pylint", "pytest", "pytest-benc
[[package]]
name = "fennel-data-lib"
-version = "0.1.24"
+version = "0.1.25"
description = ""
optional = false
python-versions = ">=3.8"
files = [
- {file = "fennel_data_lib-0.1.24-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:810537b17cc9cf253c984d48d95b22438c4734b7a3035d2144f7b024f4521b58"},
- {file = "fennel_data_lib-0.1.24-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3e1814938da9f6f82b9bce04bd95b3ba4b8f49ec4097054d46609e58c57b390"},
- {file = "fennel_data_lib-0.1.24-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dc9fbd4a6fdb71980569a82439ae7e0072981ca7454be5f5ef0834acd4cc8420"},
- {file = "fennel_data_lib-0.1.24-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ab45451797311a94d2dbeff21cd7ad10bc925087f192c0e4a6a13aa96354e377"},
- {file = "fennel_data_lib-0.1.24-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80258a4b0189d0bdf4a271b15a4358dc031b76593732d4b4d2df6dfd72428d06"},
- {file = "fennel_data_lib-0.1.24-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a6810b1a1ba217a9a1b284122fff47ef21764e20de41e1d8e0fb8174e227a86"},
- {file = "fennel_data_lib-0.1.24-cp310-cp310-manylinux_2_34_x86_64.whl", hash = "sha256:bdfb2a863b84b9238abdf5ae469bf1bbd87b5d6e3bea8defe24c83a13a7daf68"},
- {file = "fennel_data_lib-0.1.24-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d5d4c36eef520af2309ef07b328b6c72bf40bea6d481ce7a6bbb5d68edaef30b"},
- {file = "fennel_data_lib-0.1.24-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b8497f904144d86a62b3cb65f2e74799ca529ff25d30914490d71d8fa46abb46"},
- {file = "fennel_data_lib-0.1.24-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:54b0dda37d9e70c0de1f09cca3fd864ac622da35beef91bae81f7b8eaf1d3fa5"},
- {file = "fennel_data_lib-0.1.24-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1ce9e776991550b911954209d021efb36444f7c81344c0ccc8b2303d2db115ed"},
- {file = "fennel_data_lib-0.1.24-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:139f213cc2b4c655860d9367f3ff00ac941cd16865dbb4e274d0b165b6809155"},
- {file = "fennel_data_lib-0.1.24-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4a8573aa1e6604281cd86c26274973c93c2a559e6b67215328c55081411decd2"},
- {file = "fennel_data_lib-0.1.24-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f966cfa25e8a1430390b593c0cebcf38f64d4f88ca856fd680837564cf33b963"},
- {file = "fennel_data_lib-0.1.24-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d8e10fbe416723e120078d1c42ecf9f415cb0adfecbc5c1679f3f7db2b833fc"},
- {file = "fennel_data_lib-0.1.24-cp311-cp311-manylinux_2_34_x86_64.whl", hash = "sha256:c54a8841ce202a2f9c1d823a1988a654e31bf1ee8ec994d9120a15e05be8aac6"},
- {file = "fennel_data_lib-0.1.24-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47cac3a552969d36f69544c87e16727af868024acee895934da0d5250a4008fc"},
- {file = "fennel_data_lib-0.1.24-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:850e1a9e16f0a769610289a3f16020be81429b1d6a9e34062e800aace5a88122"},
- {file = "fennel_data_lib-0.1.24-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:47b19869c1338f51fd4cd749ced952cda3b6596c5777eb66eaff5a068fd82acd"},
- {file = "fennel_data_lib-0.1.24-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:077df1687e89caec85ce1f395cb786e48a9edc601fd24bf4c12ccab3485087a8"},
- {file = "fennel_data_lib-0.1.24-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0374562846d4e90f7844c8a28ed2f986594a92dfe9cfb6d8298656ef94dc76e2"},
- {file = "fennel_data_lib-0.1.24-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:db9a6f14ff4a934c9834ba3d3e8c1aa999c16ca11acbd9cbc1a42932c25075c6"},
- {file = "fennel_data_lib-0.1.24-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:be9d674efb45d6b8d94f7b7452135622048a67df5265d95dab35979476d3ca49"},
- {file = "fennel_data_lib-0.1.24-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1393db53e323097ce7d4f044de64cac94fba44b457131815a15a992d195127cc"},
- {file = "fennel_data_lib-0.1.24-cp312-cp312-manylinux_2_34_x86_64.whl", hash = "sha256:c9a3715913b42a1b4130b44d45e292630907cb4564acfc09a3dc8453bce45431"},
- {file = "fennel_data_lib-0.1.24-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4b993af888b29e074cddbac59f8a207a26c2acaabd5fc9ee16c68abf95879c81"},
- {file = "fennel_data_lib-0.1.24-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad5bec6bf17e0465cc3e0507700ec03869d848ab237d06175c0462aacdb74085"},
- {file = "fennel_data_lib-0.1.24-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:3a927a88262ee0c93909969851a9c958ecea8e0d2757cdfe73276b5f90652c3a"},
- {file = "fennel_data_lib-0.1.24-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3dcd9a6bae8984714b87926c90552505f4442c70175734595c1c3582384194d"},
- {file = "fennel_data_lib-0.1.24-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ad468415a888b5695cf186655819de2973c1744d0839f24a389e192d3c525f5a"},
- {file = "fennel_data_lib-0.1.24-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:54a597752ee872dd4c1523511d8933d4880a7eab9528c1c2b896059c6aa6bf3e"},
- {file = "fennel_data_lib-0.1.24-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1ec997610b43af6eb570c9e8f13c5a1de45f7454dca26f6a9ce80a88a3728d6b"},
- {file = "fennel_data_lib-0.1.24-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0cebdc9e295b2382e32b413129d2480da22f72b98c6253619e4a21c4173fa7f1"},
- {file = "fennel_data_lib-0.1.24-cp39-cp39-manylinux_2_34_x86_64.whl", hash = "sha256:498c3bbef1ec8f7e760ab1ba20074f256c2b37f90f2faa5e6360b30112535255"},
- {file = "fennel_data_lib-0.1.24-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:f66a6c2d7f20d4ba4d47c13adcbeefe8897ad6579b0d1817c4928e2e57627531"},
- {file = "fennel_data_lib-0.1.24-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2a5ca35ca16994ede332419331fc524704432afc1c5ef66afd84fa2c57da6bb3"},
- {file = "fennel_data_lib-0.1.24.tar.gz", hash = "sha256:0fe65710e04be1399c106ff593eaa9f4b57f5f511579ff82fec97b320d85f4d1"},
+ {file = "fennel_data_lib-0.1.25-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:1400b5f3f3d525d883779d26aac4702378db5b4a8acc6096f2abbf03675af4c6"},
+ {file = "fennel_data_lib-0.1.25-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a2eb6ebf78093e95f9e6fbc183dc37b068659a2737c0a1eab3104cbc3d7a57f7"},
+ {file = "fennel_data_lib-0.1.25-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0b1e3e647ad7e52cc76375fc1a6e16a90be9e4e6d4af1f188ddfe08d6b06f376"},
+ {file = "fennel_data_lib-0.1.25-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ca5f08611deed275ca4f7bf11a657a28ecc4eac6b28909a43261f9f076ab7318"},
+ {file = "fennel_data_lib-0.1.25-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33beaed0bafa19a7ff9d2e238e208c787f9cad58f772e974c0b3964974d7c0df"},
+ {file = "fennel_data_lib-0.1.25-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ebc93b10b63d87cecb14bb9adc2ed887989f2b505b11f72ebfe36136cb68ad2"},
+ {file = "fennel_data_lib-0.1.25-cp310-cp310-manylinux_2_34_x86_64.whl", hash = "sha256:8fdd358dee6a1151bd0e1a2c8ea3658b8fd0c2c09f90decfc98d2032cddc1d75"},
+ {file = "fennel_data_lib-0.1.25-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:67feb21127dcb175d75ef257f35d6646e8fb220aa08bfb6d6d5ea7dd42fc3fa9"},
+ {file = "fennel_data_lib-0.1.25-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2faf3ef2cb180681f36359f680fb7df4759412ae10f6bf533a68a375cf49ad18"},
+ {file = "fennel_data_lib-0.1.25-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:e4acb6e7070e52694d27329ca0e30394e5a2d1adf8f270c8f96b5e9c11cd8bb4"},
+ {file = "fennel_data_lib-0.1.25-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88cf52f24d91edc3a04aaddd0e79dd3aad35f8121d40719ff19a1a3b3c9774c1"},
+ {file = "fennel_data_lib-0.1.25-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f26555f437a2c64807e101c55b3d6c60e4b1558a774a6792ad27643a2b6305dc"},
+ {file = "fennel_data_lib-0.1.25-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c75c0ef4a91a2ca2fd6482aeb8bd951ac2aa034f0ed4a95e1237dbda3ad4c3d2"},
+ {file = "fennel_data_lib-0.1.25-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:871484118f6a851f9a1a7a1487a490ee53a2990eff37665bdf3b49c13d2eb218"},
+ {file = "fennel_data_lib-0.1.25-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0915d044846f4b8671cd06b26a043cc04aa11d7201275c11bf6cd3b61ed8e670"},
+ {file = "fennel_data_lib-0.1.25-cp311-cp311-manylinux_2_34_x86_64.whl", hash = "sha256:eaa7641d27f56cfbf39e20e340e72ef424bb43c645cad7c5c9146b63695ea022"},
+ {file = "fennel_data_lib-0.1.25-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d96c184432bec2659f370e01f0b9b40fd100adbc446f58032bc5984933206c84"},
+ {file = "fennel_data_lib-0.1.25-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a4176b1f5982bef56f73c5ff87952755f6ac9e323f1a183b6333dc6cb5d102c6"},
+ {file = "fennel_data_lib-0.1.25-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:fe99900e98f8e2f3fbe5514ed0c469fd284b7333e34c7d0e71c4dd580d3445fa"},
+ {file = "fennel_data_lib-0.1.25-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:13e2d698086214c6acd91b524bbfbcd674c73a2f9f765a348878738bcbcfe2fd"},
+ {file = "fennel_data_lib-0.1.25-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bf699de573eaec451d8772e7f78a4790b1f2f622ab3f09470ff048d6ce98717c"},
+ {file = "fennel_data_lib-0.1.25-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:03aadebe7f5ff49a5528daf44409641a88148822ea4102420fe2db1e6428fb34"},
+ {file = "fennel_data_lib-0.1.25-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6ff6efa8c4381bedc40e0acc2200ad795601ac4c491bc509eb9e177e3db8bf78"},
+ {file = "fennel_data_lib-0.1.25-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b74f63236c1a7d15260a5146099c679ffca725ba4c68d297bfcf4ffc8271ecd1"},
+ {file = "fennel_data_lib-0.1.25-cp312-cp312-manylinux_2_34_x86_64.whl", hash = "sha256:832f87853c0f741c7f22beede8805c67dfe198d585f31aa028fab516bec73a17"},
+ {file = "fennel_data_lib-0.1.25-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bb2ca03345f56be681ff9cfe655fa452042fb7daec73e0222a7aa504451c5167"},
+ {file = "fennel_data_lib-0.1.25-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d1aa9a6579e3522eeede64677badcf00c7b3c365df3a15bf5a8be2138ddfabf1"},
+ {file = "fennel_data_lib-0.1.25-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:bd2a9dd606acd96fe861e28a3080b41f8cd1ca05c132662f284c074172962b0c"},
+ {file = "fennel_data_lib-0.1.25-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3874ecc64585b2b993a9b5f4c72549e9f8d42490f6186a36cf7a82ce34012b02"},
+ {file = "fennel_data_lib-0.1.25-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:777043aa1f0360b080352903c54c9d6e63ec779ea0ddbec3d457e6983dd24336"},
+ {file = "fennel_data_lib-0.1.25-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0e80106bc7e9821ca28c24a074d7361fd848e6326644e4b891af35b0d7ed15f7"},
+ {file = "fennel_data_lib-0.1.25-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2af0e8d18d5295c973e9d61959d4d07bca49848e6b6c96e684dd37ae737ed54e"},
+ {file = "fennel_data_lib-0.1.25-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:74d4f3bbab20534b227db6b2c15fd8ea72ca3541d715168b6b8c34320aa9cf88"},
+ {file = "fennel_data_lib-0.1.25-cp39-cp39-manylinux_2_34_x86_64.whl", hash = "sha256:eba4ec03e2d8a4e1244bebc5cf7f9554ebea3d17e9547fa212f525ca0c133ad5"},
+ {file = "fennel_data_lib-0.1.25-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dda353e838b6ef04adeeb1a0116aba623eab4b3dddacd7a38dea9cfb444c7e28"},
+ {file = "fennel_data_lib-0.1.25-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9656746be7355876252fb4b8d808cadf14741d316878bd0d8da2149ef4ecd98f"},
+ {file = "fennel_data_lib-0.1.25.tar.gz", hash = "sha256:9194b244928ba7c07acefb052ed75425fbe63a9803f0e5580702ff902f42af15"},
]
[[package]]
@@ -3771,4 +3771,4 @@ type = ["pytest-mypy"]
[metadata]
lock-version = "2.0"
python-versions = "^3.9"
-content-hash = "8b8f85fde3aaeb25f9dc5cda7264e90e32645fd7221f770bb90a9c8e1bbb6768"
+content-hash = "a2fc7a796b70119c03404c978ca01393b6fd63cf84076be12826cc8ff35920c8"
diff --git a/pyproject.toml b/pyproject.toml
index ad0511f34..4281b861a 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[tool.poetry]
name = "fennel-ai"
-version = "1.5.62"
+version = "1.5.63"
description = "The modern realtime feature engineering platform"
authors = ["Fennel AI "]
packages = [{ include = "fennel" }]
@@ -20,7 +20,7 @@ pytest = "7.1.3"
pytest-rerunfailures = "^13.0"
sortedcontainers = "^2.4.0"
typing-extensions = "^4.12.0"
-fennel-data-lib = "0.1.24"
+fennel-data-lib = "0.1.25"
pyarrow = "^14.0.2"
[tool.poetry.dev-dependencies]
@@ -58,8 +58,6 @@ build-backend = "poetry.core.masonry.api"
# sdist-directory = "python_package"
# manifest-path = "../server/fennel_data_lib/Cargo.toml"
-
-# inspired from - https://github.com/pypa/pip/blob/main/pyproject.toml
# inspired from - https://github.com/pypa/pip/blob/main/pyproject.toml
# vendoring configuration