diff --git a/docs/api.yml b/docs/api.yml index 71fa7dcd..b64917e0 100644 --- a/docs/api.yml +++ b/docs/api.yml @@ -96,6 +96,7 @@ sidebar: - "api-reference/expressions/fillnull" - "api-reference/expressions/lit" - "api-reference/expressions/not" + - "api-reference/expressions/now" - "api-reference/expressions/typeof" - "api-reference/expressions/when" diff --git a/docs/examples/api-reference/expressions/basic.py b/docs/examples/api-reference/expressions/basic.py index b783c034..3a27c2e8 100644 --- a/docs/examples/api-reference/expressions/basic.py +++ b/docs/examples/api-reference/expressions/basic.py @@ -1,3 +1,5 @@ +from datetime import datetime + import pytest from typing import Optional import pandas as pd @@ -156,3 +158,26 @@ def test_lit(): df = pd.DataFrame({"x": pd.Series([1, 2, None], dtype=pd.Int64Dtype())}) assert expr.eval(df, schema={"x": Optional[int]}).tolist() == [2, 3, pd.NA] # /docsnip + + +def test_now(): + # docsnip expr_now + from fennel.expr import now, col + + # docsnip-highlight next-line + expr = now().dt.since(col("birthdate"), "year") + + assert ( + expr.typeof(schema={"birthdate": Optional[datetime]}) == Optional[int] + ) + + # can be evaluated with a dataframe + df = pd.DataFrame( + {"birthdate": [datetime(1997, 12, 24), datetime(2001, 1, 21), None]} + ) + assert expr.eval(df, schema={"birthdate": Optional[datetime]}).tolist() == [ + 26, + 23, + pd.NA, + ] + # /docsnip diff --git a/docs/pages/api-reference/expressions/now.md b/docs/pages/api-reference/expressions/now.md new file mode 100644 index 00000000..44415241 --- /dev/null +++ b/docs/pages/api-reference/expressions/now.md @@ -0,0 +1,18 @@ +--- +title: Now +order: 0 +status: published +--- +### Now + +Function to get current timestamp, similar to what `datetime.now` does in Python. + +
+
+ +#### Returns + +Returns an expression object denoting a reference to the column. The type of +the resulting expression is datetime. + diff --git a/fennel/CHANGELOG.md b/fennel/CHANGELOG.md index 8d04212c..ace4c9b0 100644 --- a/fennel/CHANGELOG.md +++ b/fennel/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +## [1.5.33] - 2024-09-30 +- Add support for now in expressions. + ## [1.5.32] - 2024-09-27 - Add dropnull to FirstK diff --git a/fennel/client_tests/test_expr.py b/fennel/client_tests/test_expr.py new file mode 100644 index 00000000..fd01f545 --- /dev/null +++ b/fennel/client_tests/test_expr.py @@ -0,0 +1,149 @@ +from datetime import datetime, timezone, timedelta +from typing import Optional + +import pandas as pd +import pytest + +from fennel._vendor import requests +from fennel.connectors import source, Webhook +from fennel.datasets import dataset, field +from fennel.expr import col +from fennel.featuresets import featureset, feature as F +from fennel.testing import mock + +webhook = Webhook(name="fennel_webhook") +__owner__ = "eng@fennel.ai" + + +@source(webhook.endpoint("UserInfoDataset"), disorder="14d", cdc="upsert") +@dataset(index=True) +class UserInfoDataset: + user_id: int = field(key=True) + name: str + birthdate: datetime + country: str + ts: datetime = field(timestamp=True) + + +@pytest.mark.integration +@mock +def test_now(client): + from fennel.expr import now + + @featureset + class UserInfoFeatures: + user_id: int + name: Optional[str] = F(UserInfoDataset.name) + birthdate: Optional[datetime] = F(UserInfoDataset.birthdate) + age: Optional[int] = F(now().dt.since(col("birthdate"), unit="year")) + country: Optional[str] = F(UserInfoDataset.country) + + # Sync the dataset + response = client.commit( + message="msg", + datasets=[UserInfoDataset], + featuresets=[UserInfoFeatures], + ) + assert response.status_code == requests.codes.OK, response.json() + + now = datetime.now(timezone.utc) + now_1y = now - timedelta(days=365) + df = pd.DataFrame( + { + "user_id": [1, 2, 3, 4, 5], + "name": ["Ross", "Monica", "Chandler", "Joey", "Rachel"], + "birthdate": [ + datetime(1970, 1, 1, tzinfo=timezone.utc), + datetime(1980, 3, 12, tzinfo=timezone.utc), + datetime(1990, 5, 15, tzinfo=timezone.utc), + datetime(1997, 12, 24, tzinfo=timezone.utc), + datetime(2001, 1, 21, tzinfo=timezone.utc), + ], + "country": ["India", "USA", "Africa", "UK", "Chile"], + "ts": [now_1y, now_1y, now_1y, now_1y, now_1y], + } + ) + response = client.log("fennel_webhook", "UserInfoDataset", df) + assert response.status_code == requests.codes.OK, response.json() + + client.sleep() + + # Querying UserInfoFeatures + df = client.query( + inputs=[UserInfoFeatures.user_id], + outputs=[ + UserInfoFeatures.name, + UserInfoFeatures.age, + UserInfoFeatures.country, + ], + input_dataframe=pd.DataFrame( + {"UserInfoFeatures.user_id": [1, 2, 3, 4, 5, 6]} + ), + ) + assert df.shape == (6, 3) + assert df["UserInfoFeatures.name"].tolist() == [ + "Ross", + "Monica", + "Chandler", + "Joey", + "Rachel", + pd.NA, + ] + assert df["UserInfoFeatures.age"].tolist() == [54, 44, 34, 26, 23, pd.NA] + assert df["UserInfoFeatures.country"].tolist() == [ + "India", + "USA", + "Africa", + "UK", + "Chile", + pd.NA, + ] + + if not client.is_integration_client(): + df = client.query_offline( + inputs=[UserInfoFeatures.user_id], + outputs=[ + UserInfoFeatures.name, + UserInfoFeatures.age, + UserInfoFeatures.country, + ], + input_dataframe=pd.DataFrame( + { + "UserInfoFeatures.user_id": [1, 2, 3, 4, 5, 6], + "timestamp": [ + now_1y, + now_1y, + now_1y, + now_1y, + now_1y, + now_1y, + ], + } + ), + timestamp_column="timestamp", + ) + assert df.shape == (6, 4) + assert df["UserInfoFeatures.name"].tolist() == [ + "Ross", + "Monica", + "Chandler", + "Joey", + "Rachel", + pd.NA, + ] + assert df["UserInfoFeatures.age"].tolist() == [ + 53, + 43, + 33, + 25, + 22, + pd.NA, + ] + assert df["UserInfoFeatures.country"].tolist() == [ + "India", + "USA", + "Africa", + "UK", + "Chile", + pd.NA, + ] diff --git a/fennel/datasets/test_invalid_dataset.py b/fennel/datasets/test_invalid_dataset.py index f4a3f8c9..7d61f8d9 100644 --- a/fennel/datasets/test_invalid_dataset.py +++ b/fennel/datasets/test_invalid_dataset.py @@ -295,7 +295,7 @@ def transform(cls, rating: Dataset): assert ( str(e2.value) - == """invalid assign - '[Pipeline:transform]->assign node' error in expression for column `movie_suffixed`: Failed to compile expression: invalid expression: both sides of '+' must be numeric types but found String & String, left: col("movie"), right: lit(String("_suffix"))""" + == """invalid assign - '[Pipeline:transform]->assign node' error in expression for column `movie_suffixed`: failed to compile expression: invalid expression: both sides of '+' must be numeric types but found String & String, left: col("movie"), right: lit(String("_suffix"))""" ) diff --git a/fennel/expr/__init__.py b/fennel/expr/__init__.py index 362f199b..43e0dc3e 100644 --- a/fennel/expr/__init__.py +++ b/fennel/expr/__init__.py @@ -6,6 +6,7 @@ var, datetime, from_epoch, + now, Expr, InvalidExprException, ) diff --git a/fennel/expr/expr.py b/fennel/expr/expr.py index 5e2c8810..cf85430c 100644 --- a/fennel/expr/expr.py +++ b/fennel/expr/expr.py @@ -7,6 +7,7 @@ from typing import Any, Callable, Dict, Type, Optional import pandas as pd +from fennel._vendor.pydantic import BaseModel # type: ignore from fennel.dtypes.dtypes import FENNEL_STRUCT, FENNEL_STRUCT_SRC_CODE from fennel.internal_lib.schema.schema import ( convert_dtype_to_arrow_type_with_nullable, @@ -17,6 +18,7 @@ from fennel_data_lib import assign, type_of, matches import fennel.gen.schema_pb2 as schema_proto +import fennel.gen.expr_pb2 as expr_proto from fennel.internal_lib.schema import ( get_datatype, cast_col_to_arrow_dtype, @@ -27,6 +29,10 @@ ) +class EvalContext(BaseModel): + now_col_name: Optional[str] = None + + class InvalidExprException(Exception): pass @@ -360,6 +366,7 @@ def eval( schema: Dict, output_dtype: Optional[Type] = None, parse=True, + context: Optional[EvalContext] = None, ) -> pd.Series: from fennel.expr.serializer import ExprSerializer @@ -410,8 +417,18 @@ def pa_to_pd(pa_data, ret_type, parse=True): ret_type = output_dtype serialized_ret_type = get_datatype(ret_type).SerializeToString() + if context is None: + serialized_context = expr_proto.EvalContext().SerializeToString() + else: + serialized_context = expr_proto.EvalContext( + **context.dict() + ).SerializeToString() arrow_col = assign( - proto_bytes, df_pa, proto_schema, serialized_ret_type + proto_bytes, + df_pa, + proto_schema, + serialized_ret_type, + serialized_context, ) return pa_to_pd(arrow_col, ret_type, parse) @@ -1089,6 +1106,14 @@ def __str__(self) -> str: return f"fillnull({self.expr}, {self.fill})" +class Now(Expr): + def __init__(self): + super(Now, self).__init__() + + def __str__(self) -> str: + return "now()" + + class MakeStruct(Expr): def __init__(self, fields: Dict[str, Expr], type: Type): self.fields = fields @@ -1183,3 +1208,7 @@ def datetime( ), DateTimeNoop(), ) + + +def now() -> Now: + return Now() diff --git a/fennel/expr/serializer.py b/fennel/expr/serializer.py index 0673ff04..df8aafb3 100644 --- a/fennel/expr/serializer.py +++ b/fennel/expr/serializer.py @@ -485,6 +485,11 @@ def visitDateTimeLiteral(self, obj): expr.datetime_literal.CopyFrom(datetime_literal) return expr + def visitNow(self, obj): + expr = proto.Expr() + expr.now.CopyFrom(proto.Now()) + 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 2be31827..ce7caf60 100644 --- a/fennel/expr/test_expr.py +++ b/fennel/expr/test_expr.py @@ -3,13 +3,17 @@ import random import pandas as pd from dataclasses import dataclass, fields -from datetime import datetime +from datetime import datetime, timezone from typing import Any, Dict, Optional, List from fennel.datasets import dataset from fennel.dtypes.dtypes import struct -from fennel.expr import col, when, lit -from fennel.expr.expr import TimeUnit, from_epoch, make_struct +from fennel.expr import col, when, lit, now +from fennel.expr.expr import ( + TimeUnit, + from_epoch, + make_struct, +) from fennel.expr.visitor import ExprPrinter, FetchReferences from fennel.expr.serializer import ExprSerializer from google.protobuf.json_format import ParseDict # type: ignore @@ -1345,3 +1349,30 @@ def test_isnull(): for case in cases: check_test_case(case) + + +def test_now(): + cases = [ + ExprTestCase( + expr=now().dt.since(col("birthdate"), unit="day"), + df=pd.DataFrame( + { + "birthdate": [ + datetime.now(timezone.utc), + datetime.now(timezone.utc), + None, + datetime.now(timezone.utc), + ], + } + ), + schema={"birthdate": Optional[datetime]}, + display='SINCE(NOW(), col("birthdate"), unit=TimeUnit.DAY)', + refs={"birthdate"}, + eval_result=[0, 0, pd.NA, 0], + expected_dtype=Optional[int], + proto_json=None, + ), + ] + + for case in cases: + check_test_case(case) diff --git a/fennel/expr/test_invalid_expr.py b/fennel/expr/test_invalid_expr.py index a26f339d..7d467bd2 100644 --- a/fennel/expr/test_invalid_expr.py +++ b/fennel/expr/test_invalid_expr.py @@ -27,7 +27,7 @@ def test_invalid_datetime(): expr.eval(df, {"a": str}) assert ( - "Failed to compile expression: invalid timezone: `America/NonYork`" + "failed to compile expression: invalid timezone: `America/NonYork`" in str(e.value) ) @@ -45,14 +45,14 @@ def test_invalid_datetime(): expr.eval(df, {"a": str}) assert ( str(e.value) - == 'Failed to evaluate expression: failed to eval expression: col("a").str.parse_datetime("%Y-%m-%d", timezone="America/New_York"), error: invalid operation: conversion from `str` to `datetime[μs, America/New_York]` failed in column \'a\' for 3 out of 3 values: ["1", "2", "3"]' + == 'failed to evaluate expression: failed to eval expression: col("a").str.parse_datetime("%Y-%m-%d", timezone="America/New_York"), error: invalid operation: conversion from `str` to `datetime[μs, America/New_York]` failed in column \'a\' for 3 out of 3 values: ["1", "2", "3"]' ) with pytest.raises(ValueError) as e: expr.eval(df, {"a": int}) assert ( str(e.value) - == """Failed to compile expression: invalid expression: expected string type for function 'Strptime { format: "%Y-%m-%d", timezone: Some("America/New_York") }' but found Int""" + == """failed to compile expression: invalid expression: expected string type for function 'Strptime { format: "%Y-%m-%d", timezone: Some("America/New_York") }' but found Int""" ) @@ -99,5 +99,5 @@ def test_invalid_parse(): expr.eval(df, {"a": str}) assert ( str(e.value) - == "Failed to evaluate expression: failed to convert polars array to fennel array for type 'Int'" + == "failed to evaluate expression: failed to convert polars array to fennel array for type 'Int'" ) diff --git a/fennel/expr/visitor.py b/fennel/expr/visitor.py index cdf6a6ed..b82ee964 100644 --- a/fennel/expr/visitor.py +++ b/fennel/expr/visitor.py @@ -51,6 +51,7 @@ DictNoop, _DateTime, DateTimeNoop, + Now, ) @@ -115,6 +116,10 @@ def visit(self, obj): elif isinstance(obj, DateTimeFromEpoch): ret = self.visitDateTimeFromEpoch(obj) + + elif isinstance(obj, Now): + ret = self.visitNow(obj) + else: raise InvalidExprException("invalid expression type: %s" % obj) @@ -180,6 +185,9 @@ def visitDateTimeFromEpoch(self, obj): def visitDateTimeLiteral(self, obj): raise NotImplementedError + def visitNow(self, obj): + raise NotImplementedError + class ExprPrinter(Visitor): @@ -344,6 +352,9 @@ def visitDateTimeFromEpoch(self, obj): def visitDateTimeLiteral(self, obj): return f"DATETIME({obj.year}, {obj.month}, {obj.day}, {obj.hour}, {obj.minute}, {obj.second}, {obj.microsecond}, timezone={obj.timezone})" + def visitNow(self, obj): + return "NOW()" + class FetchReferences(Visitor): @@ -444,3 +455,6 @@ def visitDateTimeFromEpoch(self, obj): def visitDateTimeLiteral(self, obj): pass + + def visitNow(self, obj): + pass diff --git a/fennel/gen/expr_pb2.py b/fennel/gen/expr_pb2.py index 69df78aa..e14582da 100644 --- a/fennel/gen/expr_pb2.py +++ b/fennel/gen/expr_pb2.py @@ -14,7 +14,7 @@ import fennel.gen.schema_pb2 as schema__pb2 -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\nexpr.proto\x12\x11\x66\x65nnel.proto.expr\x1a\x0cschema.proto\"\xc1\x06\n\x04\x45xpr\x12%\n\x03ref\x18\x01 \x01(\x0b\x32\x16.fennel.proto.expr.RefH\x00\x12\x36\n\x0cjson_literal\x18\x02 \x01(\x0b\x32\x1e.fennel.proto.expr.JsonLiteralH\x00\x12)\n\x05unary\x18\x04 \x01(\x0b\x32\x18.fennel.proto.expr.UnaryH\x00\x12\'\n\x04\x63\x61se\x18\x05 \x01(\x0b\x32\x17.fennel.proto.expr.CaseH\x00\x12+\n\x06\x62inary\x18\x06 \x01(\x0b\x32\x19.fennel.proto.expr.BinaryH\x00\x12+\n\x06isnull\x18\x07 \x01(\x0b\x32\x19.fennel.proto.expr.IsNullH\x00\x12/\n\x08\x66illnull\x18\x08 \x01(\x0b\x32\x1b.fennel.proto.expr.FillNullH\x00\x12,\n\x07list_fn\x18\t \x01(\x0b\x32\x19.fennel.proto.expr.ListFnH\x00\x12,\n\x07math_fn\x18\n \x01(\x0b\x32\x19.fennel.proto.expr.MathFnH\x00\x12\x30\n\tstruct_fn\x18\x0b \x01(\x0b\x32\x1b.fennel.proto.expr.StructFnH\x00\x12,\n\x07\x64ict_fn\x18\x0c \x01(\x0b\x32\x19.fennel.proto.expr.DictFnH\x00\x12\x30\n\tstring_fn\x18\r \x01(\x0b\x32\x1b.fennel.proto.expr.StringFnH\x00\x12\x34\n\x0b\x64\x61tetime_fn\x18\x0e \x01(\x0b\x32\x1d.fennel.proto.expr.DateTimeFnH\x00\x12>\n\x10\x64\x61tetime_literal\x18\x0f \x01(\x0b\x32\".fennel.proto.expr.DatetimeLiteralH\x00\x12\x34\n\x0bmake_struct\x18\x10 \x01(\x0b\x32\x1d.fennel.proto.expr.MakeStructH\x00\x12\x32\n\nfrom_epoch\x18\x11 \x01(\x0b\x32\x1c.fennel.proto.expr.FromEpochH\x00\x12%\n\x03var\x18\x12 \x01(\x0b\x32\x16.fennel.proto.expr.VarH\x00\x42\x06\n\x04node\"\x13\n\x03Var\x12\x0c\n\x04name\x18\x01 \x01(\t\"a\n\tFromEpoch\x12)\n\x08\x64uration\x18\x01 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\x12)\n\x04unit\x18\x02 \x01(\x0e\x32\x1b.fennel.proto.expr.TimeUnit\"\xad\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-\n\x08timezone\x18\x08 \x01(\x0b\x32\x1b.fennel.proto.expr.Timezone\"\xc5\x01\n\nMakeStruct\x12\x34\n\x0bstruct_type\x18\x01 \x01(\x0b\x32\x1f.fennel.proto.schema.StructType\x12\x39\n\x06\x66ields\x18\x02 \x03(\x0b\x32).fennel.proto.expr.MakeStruct.FieldsEntry\x1a\x46\n\x0b\x46ieldsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.fennel.proto.expr.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\"Y\n\x05Unary\x12&\n\x02op\x18\x01 \x01(\x0e\x32\x1a.fennel.proto.expr.UnaryOp\x12(\n\x07operand\x18\x02 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\"}\n\x06\x42inary\x12%\n\x04left\x18\x01 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\x12&\n\x05right\x18\x02 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\x12$\n\x02op\x18\x03 \x01(\x0e\x32\x18.fennel.proto.expr.BinOp\"b\n\x04\x43\x61se\x12.\n\twhen_then\x18\x01 \x03(\x0b\x32\x1b.fennel.proto.expr.WhenThen\x12*\n\totherwise\x18\x02 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\"X\n\x08WhenThen\x12%\n\x04when\x18\x01 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\x12%\n\x04then\x18\x02 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\"2\n\x06IsNull\x12(\n\x07operand\x18\x01 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\"[\n\x08\x46illNull\x12(\n\x07operand\x18\x01 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\x12%\n\x04\x66ill\x18\x02 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\"\xa3\x04\n\x06ListOp\x12%\n\x03len\x18\x01 \x01(\x0b\x32\x16.fennel.proto.expr.LenH\x00\x12&\n\x03get\x18\x02 \x01(\x0b\x32\x17.fennel.proto.expr.ExprH\x00\x12/\n\x08\x63ontains\x18\x03 \x01(\x0b\x32\x1b.fennel.proto.expr.ContainsH\x00\x12.\n\x08has_null\x18\x04 \x01(\x0b\x32\x1a.fennel.proto.expr.HasNullH\x00\x12)\n\x03sum\x18\x05 \x01(\x0b\x32\x1a.fennel.proto.expr.ListSumH\x00\x12)\n\x03min\x18\x06 \x01(\x0b\x32\x1a.fennel.proto.expr.ListMinH\x00\x12)\n\x03max\x18\x07 \x01(\x0b\x32\x1a.fennel.proto.expr.ListMaxH\x00\x12)\n\x03\x61ll\x18\x08 \x01(\x0b\x32\x1a.fennel.proto.expr.ListAllH\x00\x12)\n\x03\x61ny\x18\t \x01(\x0b\x32\x1a.fennel.proto.expr.ListAnyH\x00\x12+\n\x04mean\x18\n \x01(\x0b\x32\x1b.fennel.proto.expr.ListMeanH\x00\x12/\n\x06\x66ilter\x18\x0b \x01(\x0b\x32\x1d.fennel.proto.expr.ListFilterH\x00\x12)\n\x03map\x18\x0c \x01(\x0b\x32\x1a.fennel.proto.expr.ListMapH\x00\x42\t\n\x07\x66n_type\"E\n\nListFilter\x12\x0b\n\x03var\x18\x01 \x01(\t\x12*\n\tpredicate\x18\x02 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\"A\n\x07ListMap\x12\x0b\n\x03var\x18\x01 \x01(\t\x12)\n\x08map_expr\x18\x02 \x01(\x0b\x32\x17.fennel.proto.expr.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\"4\n\x08\x43ontains\x12(\n\x07\x65lement\x18\x01 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\"V\n\x06ListFn\x12%\n\x04list\x18\x01 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\x12%\n\x02\x66n\x18\x02 \x01(\x0b\x32\x19.fennel.proto.expr.ListOp\"\xb9\x01\n\x06MathOp\x12)\n\x05round\x18\x01 \x01(\x0b\x32\x18.fennel.proto.expr.RoundH\x00\x12%\n\x03\x61\x62s\x18\x02 \x01(\x0b\x32\x16.fennel.proto.expr.AbsH\x00\x12\'\n\x04\x63\x65il\x18\x03 \x01(\x0b\x32\x17.fennel.proto.expr.CeilH\x00\x12)\n\x05\x66loor\x18\x04 \x01(\x0b\x32\x18.fennel.proto.expr.FloorH\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\"Y\n\x06MathFn\x12(\n\x07operand\x18\x01 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\x12%\n\x02\x66n\x18\x02 \x01(\x0b\x32\x19.fennel.proto.expr.MathOp\"&\n\x08StructOp\x12\x0f\n\x05\x66ield\x18\x01 \x01(\tH\x00\x42\t\n\x07\x66n_type\"\\\n\x08StructFn\x12\'\n\x06struct\x18\x01 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\x12\'\n\x02\x66n\x18\x02 \x01(\x0b\x32\x1b.fennel.proto.expr.StructOp\"a\n\x07\x44ictGet\x12&\n\x05\x66ield\x18\x01 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\x12.\n\rdefault_value\x18\x03 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\"\x96\x01\n\x06\x44ictOp\x12%\n\x03len\x18\x01 \x01(\x0b\x32\x16.fennel.proto.expr.LenH\x00\x12)\n\x03get\x18\x02 \x01(\x0b\x32\x1a.fennel.proto.expr.DictGetH\x00\x12/\n\x08\x63ontains\x18\x03 \x01(\x0b\x32\x1b.fennel.proto.expr.ContainsH\x00\x42\t\n\x07\x66n_type\"V\n\x06\x44ictFn\x12%\n\x04\x64ict\x18\x01 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\x12%\n\x02\x66n\x18\x02 \x01(\x0b\x32\x19.fennel.proto.expr.DictOp\"\xc5\x03\n\x08StringOp\x12%\n\x03len\x18\x01 \x01(\x0b\x32\x16.fennel.proto.expr.LenH\x00\x12-\n\x07tolower\x18\x02 \x01(\x0b\x32\x1a.fennel.proto.expr.ToLowerH\x00\x12-\n\x07toupper\x18\x03 \x01(\x0b\x32\x1a.fennel.proto.expr.ToUpperH\x00\x12/\n\x08\x63ontains\x18\x04 \x01(\x0b\x32\x1b.fennel.proto.expr.ContainsH\x00\x12\x33\n\nstartswith\x18\x05 \x01(\x0b\x32\x1d.fennel.proto.expr.StartsWithH\x00\x12/\n\x08\x65ndswith\x18\x06 \x01(\x0b\x32\x1b.fennel.proto.expr.EndsWithH\x00\x12+\n\x06\x63oncat\x18\x07 \x01(\x0b\x32\x19.fennel.proto.expr.ConcatH\x00\x12/\n\x08strptime\x18\x08 \x01(\x0b\x32\x1b.fennel.proto.expr.StrptimeH\x00\x12\x34\n\x0bjson_decode\x18\t \x01(\x0b\x32\x1d.fennel.proto.expr.JsonDecodeH\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\"I\n\x08Strptime\x12\x0e\n\x06\x66ormat\x18\x01 \x01(\t\x12-\n\x08timezone\x18\x02 \x01(\x0b\x32\x1b.fennel.proto.expr.Timezone\"\t\n\x07ToLower\"\t\n\x07ToUpper\"2\n\nStartsWith\x12$\n\x03key\x18\x01 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\"0\n\x08\x45ndsWith\x12$\n\x03key\x18\x01 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\"0\n\x06\x43oncat\x12&\n\x05other\x18\x01 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\"\\\n\x08StringFn\x12\'\n\x06string\x18\x01 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\x12\'\n\x02\x66n\x18\x02 \x01(\x0b\x32\x1b.fennel.proto.expr.StringOp\"b\n\nDateTimeFn\x12)\n\x08\x64\x61tetime\x18\x01 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\x12)\n\x02\x66n\x18\x02 \x01(\x0b\x32\x1d.fennel.proto.expr.DateTimeOp\"\xd2\x01\n\nDateTimeOp\x12)\n\x05since\x18\x01 \x01(\x0b\x32\x18.fennel.proto.expr.SinceH\x00\x12\x34\n\x0bsince_epoch\x18\x02 \x01(\x0b\x32\x1d.fennel.proto.expr.SinceEpochH\x00\x12/\n\x08strftime\x18\x03 \x01(\x0b\x32\x1b.fennel.proto.expr.StrftimeH\x00\x12\'\n\x04part\x18\x04 \x01(\x0b\x32\x17.fennel.proto.expr.PartH\x00\x42\t\n\x07\x66n_type\"Z\n\x05Since\x12&\n\x05other\x18\x01 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\x12)\n\x04unit\x18\x02 \x01(\x0e\x32\x1b.fennel.proto.expr.TimeUnit\"7\n\nSinceEpoch\x12)\n\x04unit\x18\x01 \x01(\x0e\x32\x1b.fennel.proto.expr.TimeUnit\"I\n\x08Strftime\x12\x0e\n\x06\x66ormat\x18\x01 \x01(\t\x12-\n\x08timezone\x18\x02 \x01(\x0b\x32\x1b.fennel.proto.expr.Timezone\"`\n\x04Part\x12)\n\x04unit\x18\x01 \x01(\x0e\x32\x1b.fennel.proto.expr.TimeUnit\x12-\n\x08timezone\x18\x02 \x01(\x0b\x32\x1b.fennel.proto.expr.Timezone*\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\nexpr.proto\x12\x11\x66\x65nnel.proto.expr\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\"\xe8\x06\n\x04\x45xpr\x12%\n\x03ref\x18\x01 \x01(\x0b\x32\x16.fennel.proto.expr.RefH\x00\x12\x36\n\x0cjson_literal\x18\x02 \x01(\x0b\x32\x1e.fennel.proto.expr.JsonLiteralH\x00\x12)\n\x05unary\x18\x04 \x01(\x0b\x32\x18.fennel.proto.expr.UnaryH\x00\x12\'\n\x04\x63\x61se\x18\x05 \x01(\x0b\x32\x17.fennel.proto.expr.CaseH\x00\x12+\n\x06\x62inary\x18\x06 \x01(\x0b\x32\x19.fennel.proto.expr.BinaryH\x00\x12+\n\x06isnull\x18\x07 \x01(\x0b\x32\x19.fennel.proto.expr.IsNullH\x00\x12/\n\x08\x66illnull\x18\x08 \x01(\x0b\x32\x1b.fennel.proto.expr.FillNullH\x00\x12,\n\x07list_fn\x18\t \x01(\x0b\x32\x19.fennel.proto.expr.ListFnH\x00\x12,\n\x07math_fn\x18\n \x01(\x0b\x32\x19.fennel.proto.expr.MathFnH\x00\x12\x30\n\tstruct_fn\x18\x0b \x01(\x0b\x32\x1b.fennel.proto.expr.StructFnH\x00\x12,\n\x07\x64ict_fn\x18\x0c \x01(\x0b\x32\x19.fennel.proto.expr.DictFnH\x00\x12\x30\n\tstring_fn\x18\r \x01(\x0b\x32\x1b.fennel.proto.expr.StringFnH\x00\x12\x34\n\x0b\x64\x61tetime_fn\x18\x0e \x01(\x0b\x32\x1d.fennel.proto.expr.DateTimeFnH\x00\x12>\n\x10\x64\x61tetime_literal\x18\x0f \x01(\x0b\x32\".fennel.proto.expr.DatetimeLiteralH\x00\x12\x34\n\x0bmake_struct\x18\x10 \x01(\x0b\x32\x1d.fennel.proto.expr.MakeStructH\x00\x12\x32\n\nfrom_epoch\x18\x11 \x01(\x0b\x32\x1c.fennel.proto.expr.FromEpochH\x00\x12%\n\x03var\x18\x12 \x01(\x0b\x32\x16.fennel.proto.expr.VarH\x00\x12%\n\x03now\x18\x13 \x01(\x0b\x32\x16.fennel.proto.expr.NowH\x00\x42\x06\n\x04node\"\x05\n\x03Now\"\x13\n\x03Var\x12\x0c\n\x04name\x18\x01 \x01(\t\"a\n\tFromEpoch\x12)\n\x08\x64uration\x18\x01 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\x12)\n\x04unit\x18\x02 \x01(\x0e\x32\x1b.fennel.proto.expr.TimeUnit\"\xad\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-\n\x08timezone\x18\x08 \x01(\x0b\x32\x1b.fennel.proto.expr.Timezone\"\xc5\x01\n\nMakeStruct\x12\x34\n\x0bstruct_type\x18\x01 \x01(\x0b\x32\x1f.fennel.proto.schema.StructType\x12\x39\n\x06\x66ields\x18\x02 \x03(\x0b\x32).fennel.proto.expr.MakeStruct.FieldsEntry\x1a\x46\n\x0b\x46ieldsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.fennel.proto.expr.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\"Y\n\x05Unary\x12&\n\x02op\x18\x01 \x01(\x0e\x32\x1a.fennel.proto.expr.UnaryOp\x12(\n\x07operand\x18\x02 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\"}\n\x06\x42inary\x12%\n\x04left\x18\x01 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\x12&\n\x05right\x18\x02 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\x12$\n\x02op\x18\x03 \x01(\x0e\x32\x18.fennel.proto.expr.BinOp\"b\n\x04\x43\x61se\x12.\n\twhen_then\x18\x01 \x03(\x0b\x32\x1b.fennel.proto.expr.WhenThen\x12*\n\totherwise\x18\x02 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\"X\n\x08WhenThen\x12%\n\x04when\x18\x01 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\x12%\n\x04then\x18\x02 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\"2\n\x06IsNull\x12(\n\x07operand\x18\x01 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\"[\n\x08\x46illNull\x12(\n\x07operand\x18\x01 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\x12%\n\x04\x66ill\x18\x02 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\"\xa3\x04\n\x06ListOp\x12%\n\x03len\x18\x01 \x01(\x0b\x32\x16.fennel.proto.expr.LenH\x00\x12&\n\x03get\x18\x02 \x01(\x0b\x32\x17.fennel.proto.expr.ExprH\x00\x12/\n\x08\x63ontains\x18\x03 \x01(\x0b\x32\x1b.fennel.proto.expr.ContainsH\x00\x12.\n\x08has_null\x18\x04 \x01(\x0b\x32\x1a.fennel.proto.expr.HasNullH\x00\x12)\n\x03sum\x18\x05 \x01(\x0b\x32\x1a.fennel.proto.expr.ListSumH\x00\x12)\n\x03min\x18\x06 \x01(\x0b\x32\x1a.fennel.proto.expr.ListMinH\x00\x12)\n\x03max\x18\x07 \x01(\x0b\x32\x1a.fennel.proto.expr.ListMaxH\x00\x12)\n\x03\x61ll\x18\x08 \x01(\x0b\x32\x1a.fennel.proto.expr.ListAllH\x00\x12)\n\x03\x61ny\x18\t \x01(\x0b\x32\x1a.fennel.proto.expr.ListAnyH\x00\x12+\n\x04mean\x18\n \x01(\x0b\x32\x1b.fennel.proto.expr.ListMeanH\x00\x12/\n\x06\x66ilter\x18\x0b \x01(\x0b\x32\x1d.fennel.proto.expr.ListFilterH\x00\x12)\n\x03map\x18\x0c \x01(\x0b\x32\x1a.fennel.proto.expr.ListMapH\x00\x42\t\n\x07\x66n_type\"E\n\nListFilter\x12\x0b\n\x03var\x18\x01 \x01(\t\x12*\n\tpredicate\x18\x02 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\"A\n\x07ListMap\x12\x0b\n\x03var\x18\x01 \x01(\t\x12)\n\x08map_expr\x18\x02 \x01(\x0b\x32\x17.fennel.proto.expr.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\"4\n\x08\x43ontains\x12(\n\x07\x65lement\x18\x01 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\"V\n\x06ListFn\x12%\n\x04list\x18\x01 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\x12%\n\x02\x66n\x18\x02 \x01(\x0b\x32\x19.fennel.proto.expr.ListOp\"\xb9\x01\n\x06MathOp\x12)\n\x05round\x18\x01 \x01(\x0b\x32\x18.fennel.proto.expr.RoundH\x00\x12%\n\x03\x61\x62s\x18\x02 \x01(\x0b\x32\x16.fennel.proto.expr.AbsH\x00\x12\'\n\x04\x63\x65il\x18\x03 \x01(\x0b\x32\x17.fennel.proto.expr.CeilH\x00\x12)\n\x05\x66loor\x18\x04 \x01(\x0b\x32\x18.fennel.proto.expr.FloorH\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\"Y\n\x06MathFn\x12(\n\x07operand\x18\x01 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\x12%\n\x02\x66n\x18\x02 \x01(\x0b\x32\x19.fennel.proto.expr.MathOp\"&\n\x08StructOp\x12\x0f\n\x05\x66ield\x18\x01 \x01(\tH\x00\x42\t\n\x07\x66n_type\"\\\n\x08StructFn\x12\'\n\x06struct\x18\x01 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\x12\'\n\x02\x66n\x18\x02 \x01(\x0b\x32\x1b.fennel.proto.expr.StructOp\"a\n\x07\x44ictGet\x12&\n\x05\x66ield\x18\x01 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\x12.\n\rdefault_value\x18\x03 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\"\x96\x01\n\x06\x44ictOp\x12%\n\x03len\x18\x01 \x01(\x0b\x32\x16.fennel.proto.expr.LenH\x00\x12)\n\x03get\x18\x02 \x01(\x0b\x32\x1a.fennel.proto.expr.DictGetH\x00\x12/\n\x08\x63ontains\x18\x03 \x01(\x0b\x32\x1b.fennel.proto.expr.ContainsH\x00\x42\t\n\x07\x66n_type\"V\n\x06\x44ictFn\x12%\n\x04\x64ict\x18\x01 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\x12%\n\x02\x66n\x18\x02 \x01(\x0b\x32\x19.fennel.proto.expr.DictOp\"\xc5\x03\n\x08StringOp\x12%\n\x03len\x18\x01 \x01(\x0b\x32\x16.fennel.proto.expr.LenH\x00\x12-\n\x07tolower\x18\x02 \x01(\x0b\x32\x1a.fennel.proto.expr.ToLowerH\x00\x12-\n\x07toupper\x18\x03 \x01(\x0b\x32\x1a.fennel.proto.expr.ToUpperH\x00\x12/\n\x08\x63ontains\x18\x04 \x01(\x0b\x32\x1b.fennel.proto.expr.ContainsH\x00\x12\x33\n\nstartswith\x18\x05 \x01(\x0b\x32\x1d.fennel.proto.expr.StartsWithH\x00\x12/\n\x08\x65ndswith\x18\x06 \x01(\x0b\x32\x1b.fennel.proto.expr.EndsWithH\x00\x12+\n\x06\x63oncat\x18\x07 \x01(\x0b\x32\x19.fennel.proto.expr.ConcatH\x00\x12/\n\x08strptime\x18\x08 \x01(\x0b\x32\x1b.fennel.proto.expr.StrptimeH\x00\x12\x34\n\x0bjson_decode\x18\t \x01(\x0b\x32\x1d.fennel.proto.expr.JsonDecodeH\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\"I\n\x08Strptime\x12\x0e\n\x06\x66ormat\x18\x01 \x01(\t\x12-\n\x08timezone\x18\x02 \x01(\x0b\x32\x1b.fennel.proto.expr.Timezone\"\t\n\x07ToLower\"\t\n\x07ToUpper\"2\n\nStartsWith\x12$\n\x03key\x18\x01 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\"0\n\x08\x45ndsWith\x12$\n\x03key\x18\x01 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\"0\n\x06\x43oncat\x12&\n\x05other\x18\x01 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\"\\\n\x08StringFn\x12\'\n\x06string\x18\x01 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\x12\'\n\x02\x66n\x18\x02 \x01(\x0b\x32\x1b.fennel.proto.expr.StringOp\"b\n\nDateTimeFn\x12)\n\x08\x64\x61tetime\x18\x01 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\x12)\n\x02\x66n\x18\x02 \x01(\x0b\x32\x1d.fennel.proto.expr.DateTimeOp\"\xd2\x01\n\nDateTimeOp\x12)\n\x05since\x18\x01 \x01(\x0b\x32\x18.fennel.proto.expr.SinceH\x00\x12\x34\n\x0bsince_epoch\x18\x02 \x01(\x0b\x32\x1d.fennel.proto.expr.SinceEpochH\x00\x12/\n\x08strftime\x18\x03 \x01(\x0b\x32\x1b.fennel.proto.expr.StrftimeH\x00\x12\'\n\x04part\x18\x04 \x01(\x0b\x32\x17.fennel.proto.expr.PartH\x00\x42\t\n\x07\x66n_type\"Z\n\x05Since\x12&\n\x05other\x18\x01 \x01(\x0b\x32\x17.fennel.proto.expr.Expr\x12)\n\x04unit\x18\x02 \x01(\x0e\x32\x1b.fennel.proto.expr.TimeUnit\"7\n\nSinceEpoch\x12)\n\x04unit\x18\x01 \x01(\x0e\x32\x1b.fennel.proto.expr.TimeUnit\"I\n\x08Strftime\x12\x0e\n\x06\x66ormat\x18\x01 \x01(\t\x12-\n\x08timezone\x18\x02 \x01(\x0b\x32\x1b.fennel.proto.expr.Timezone\"`\n\x04Part\x12)\n\x04unit\x18\x01 \x01(\x0e\x32\x1b.fennel.proto.expr.TimeUnit\x12-\n\x08timezone\x18\x02 \x01(\x0b\x32\x1b.fennel.proto.expr.Timezone*\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) @@ -23,118 +23,122 @@ DESCRIPTOR._options = None _globals['_MAKESTRUCT_FIELDSENTRY']._options = None _globals['_MAKESTRUCT_FIELDSENTRY']._serialized_options = b'8\001' - _globals['_UNARYOP']._serialized_start=5275 - _globals['_UNARYOP']._serialized_end=5302 - _globals['_BINOP']._serialized_start=5305 - _globals['_BINOP']._serialized_end=5439 - _globals['_TIMEUNIT']._serialized_start=5442 - _globals['_TIMEUNIT']._serialized_end=5573 - _globals['_EXPR']._serialized_start=48 - _globals['_EXPR']._serialized_end=881 - _globals['_VAR']._serialized_start=883 - _globals['_VAR']._serialized_end=902 - _globals['_FROMEPOCH']._serialized_start=904 - _globals['_FROMEPOCH']._serialized_end=1001 - _globals['_DATETIMELITERAL']._serialized_start=1004 - _globals['_DATETIMELITERAL']._serialized_end=1177 - _globals['_MAKESTRUCT']._serialized_start=1180 - _globals['_MAKESTRUCT']._serialized_end=1377 - _globals['_MAKESTRUCT_FIELDSENTRY']._serialized_start=1307 - _globals['_MAKESTRUCT_FIELDSENTRY']._serialized_end=1377 - _globals['_JSONLITERAL']._serialized_start=1379 - _globals['_JSONLITERAL']._serialized_end=1455 - _globals['_REF']._serialized_start=1457 - _globals['_REF']._serialized_end=1476 - _globals['_UNARY']._serialized_start=1478 - _globals['_UNARY']._serialized_end=1567 - _globals['_BINARY']._serialized_start=1569 - _globals['_BINARY']._serialized_end=1694 - _globals['_CASE']._serialized_start=1696 - _globals['_CASE']._serialized_end=1794 - _globals['_WHENTHEN']._serialized_start=1796 - _globals['_WHENTHEN']._serialized_end=1884 - _globals['_ISNULL']._serialized_start=1886 - _globals['_ISNULL']._serialized_end=1936 - _globals['_FILLNULL']._serialized_start=1938 - _globals['_FILLNULL']._serialized_end=2029 - _globals['_LISTOP']._serialized_start=2032 - _globals['_LISTOP']._serialized_end=2579 - _globals['_LISTFILTER']._serialized_start=2581 - _globals['_LISTFILTER']._serialized_end=2650 - _globals['_LISTMAP']._serialized_start=2652 - _globals['_LISTMAP']._serialized_end=2717 - _globals['_LISTSUM']._serialized_start=2719 - _globals['_LISTSUM']._serialized_end=2728 - _globals['_LISTMIN']._serialized_start=2730 - _globals['_LISTMIN']._serialized_end=2739 - _globals['_LISTMEAN']._serialized_start=2741 - _globals['_LISTMEAN']._serialized_end=2751 - _globals['_LISTMAX']._serialized_start=2753 - _globals['_LISTMAX']._serialized_end=2762 - _globals['_LISTALL']._serialized_start=2764 - _globals['_LISTALL']._serialized_end=2773 - _globals['_LISTANY']._serialized_start=2775 - _globals['_LISTANY']._serialized_end=2784 - _globals['_LEN']._serialized_start=2786 - _globals['_LEN']._serialized_end=2791 - _globals['_HASNULL']._serialized_start=2793 - _globals['_HASNULL']._serialized_end=2802 - _globals['_CONTAINS']._serialized_start=2804 - _globals['_CONTAINS']._serialized_end=2856 - _globals['_LISTFN']._serialized_start=2858 - _globals['_LISTFN']._serialized_end=2944 - _globals['_MATHOP']._serialized_start=2947 - _globals['_MATHOP']._serialized_end=3132 - _globals['_ROUND']._serialized_start=3134 - _globals['_ROUND']._serialized_end=3160 - _globals['_ABS']._serialized_start=3162 - _globals['_ABS']._serialized_end=3167 - _globals['_CEIL']._serialized_start=3169 - _globals['_CEIL']._serialized_end=3175 - _globals['_FLOOR']._serialized_start=3177 - _globals['_FLOOR']._serialized_end=3184 - _globals['_MATHFN']._serialized_start=3186 - _globals['_MATHFN']._serialized_end=3275 - _globals['_STRUCTOP']._serialized_start=3277 - _globals['_STRUCTOP']._serialized_end=3315 - _globals['_STRUCTFN']._serialized_start=3317 - _globals['_STRUCTFN']._serialized_end=3409 - _globals['_DICTGET']._serialized_start=3411 - _globals['_DICTGET']._serialized_end=3508 - _globals['_DICTOP']._serialized_start=3511 - _globals['_DICTOP']._serialized_end=3661 - _globals['_DICTFN']._serialized_start=3663 - _globals['_DICTFN']._serialized_end=3749 - _globals['_STRINGOP']._serialized_start=3752 - _globals['_STRINGOP']._serialized_end=4205 - _globals['_TIMEZONE']._serialized_start=4207 - _globals['_TIMEZONE']._serialized_end=4235 - _globals['_JSONDECODE']._serialized_start=4237 - _globals['_JSONDECODE']._serialized_end=4295 - _globals['_STRPTIME']._serialized_start=4297 - _globals['_STRPTIME']._serialized_end=4370 - _globals['_TOLOWER']._serialized_start=4372 - _globals['_TOLOWER']._serialized_end=4381 - _globals['_TOUPPER']._serialized_start=4383 - _globals['_TOUPPER']._serialized_end=4392 - _globals['_STARTSWITH']._serialized_start=4394 - _globals['_STARTSWITH']._serialized_end=4444 - _globals['_ENDSWITH']._serialized_start=4446 - _globals['_ENDSWITH']._serialized_end=4494 - _globals['_CONCAT']._serialized_start=4496 - _globals['_CONCAT']._serialized_end=4544 - _globals['_STRINGFN']._serialized_start=4546 - _globals['_STRINGFN']._serialized_end=4638 - _globals['_DATETIMEFN']._serialized_start=4640 - _globals['_DATETIMEFN']._serialized_end=4738 - _globals['_DATETIMEOP']._serialized_start=4741 - _globals['_DATETIMEOP']._serialized_end=4951 - _globals['_SINCE']._serialized_start=4953 - _globals['_SINCE']._serialized_end=5043 - _globals['_SINCEEPOCH']._serialized_start=5045 - _globals['_SINCEEPOCH']._serialized_end=5100 - _globals['_STRFTIME']._serialized_start=5102 - _globals['_STRFTIME']._serialized_end=5175 - _globals['_PART']._serialized_start=5177 - _globals['_PART']._serialized_end=5273 + _globals['_UNARYOP']._serialized_start=5380 + _globals['_UNARYOP']._serialized_end=5407 + _globals['_BINOP']._serialized_start=5410 + _globals['_BINOP']._serialized_end=5544 + _globals['_TIMEUNIT']._serialized_start=5547 + _globals['_TIMEUNIT']._serialized_end=5678 + _globals['_EVALCONTEXT']._serialized_start=47 + _globals['_EVALCONTEXT']._serialized_end=104 + _globals['_EXPR']._serialized_start=107 + _globals['_EXPR']._serialized_end=979 + _globals['_NOW']._serialized_start=981 + _globals['_NOW']._serialized_end=986 + _globals['_VAR']._serialized_start=988 + _globals['_VAR']._serialized_end=1007 + _globals['_FROMEPOCH']._serialized_start=1009 + _globals['_FROMEPOCH']._serialized_end=1106 + _globals['_DATETIMELITERAL']._serialized_start=1109 + _globals['_DATETIMELITERAL']._serialized_end=1282 + _globals['_MAKESTRUCT']._serialized_start=1285 + _globals['_MAKESTRUCT']._serialized_end=1482 + _globals['_MAKESTRUCT_FIELDSENTRY']._serialized_start=1412 + _globals['_MAKESTRUCT_FIELDSENTRY']._serialized_end=1482 + _globals['_JSONLITERAL']._serialized_start=1484 + _globals['_JSONLITERAL']._serialized_end=1560 + _globals['_REF']._serialized_start=1562 + _globals['_REF']._serialized_end=1581 + _globals['_UNARY']._serialized_start=1583 + _globals['_UNARY']._serialized_end=1672 + _globals['_BINARY']._serialized_start=1674 + _globals['_BINARY']._serialized_end=1799 + _globals['_CASE']._serialized_start=1801 + _globals['_CASE']._serialized_end=1899 + _globals['_WHENTHEN']._serialized_start=1901 + _globals['_WHENTHEN']._serialized_end=1989 + _globals['_ISNULL']._serialized_start=1991 + _globals['_ISNULL']._serialized_end=2041 + _globals['_FILLNULL']._serialized_start=2043 + _globals['_FILLNULL']._serialized_end=2134 + _globals['_LISTOP']._serialized_start=2137 + _globals['_LISTOP']._serialized_end=2684 + _globals['_LISTFILTER']._serialized_start=2686 + _globals['_LISTFILTER']._serialized_end=2755 + _globals['_LISTMAP']._serialized_start=2757 + _globals['_LISTMAP']._serialized_end=2822 + _globals['_LISTSUM']._serialized_start=2824 + _globals['_LISTSUM']._serialized_end=2833 + _globals['_LISTMIN']._serialized_start=2835 + _globals['_LISTMIN']._serialized_end=2844 + _globals['_LISTMEAN']._serialized_start=2846 + _globals['_LISTMEAN']._serialized_end=2856 + _globals['_LISTMAX']._serialized_start=2858 + _globals['_LISTMAX']._serialized_end=2867 + _globals['_LISTALL']._serialized_start=2869 + _globals['_LISTALL']._serialized_end=2878 + _globals['_LISTANY']._serialized_start=2880 + _globals['_LISTANY']._serialized_end=2889 + _globals['_LEN']._serialized_start=2891 + _globals['_LEN']._serialized_end=2896 + _globals['_HASNULL']._serialized_start=2898 + _globals['_HASNULL']._serialized_end=2907 + _globals['_CONTAINS']._serialized_start=2909 + _globals['_CONTAINS']._serialized_end=2961 + _globals['_LISTFN']._serialized_start=2963 + _globals['_LISTFN']._serialized_end=3049 + _globals['_MATHOP']._serialized_start=3052 + _globals['_MATHOP']._serialized_end=3237 + _globals['_ROUND']._serialized_start=3239 + _globals['_ROUND']._serialized_end=3265 + _globals['_ABS']._serialized_start=3267 + _globals['_ABS']._serialized_end=3272 + _globals['_CEIL']._serialized_start=3274 + _globals['_CEIL']._serialized_end=3280 + _globals['_FLOOR']._serialized_start=3282 + _globals['_FLOOR']._serialized_end=3289 + _globals['_MATHFN']._serialized_start=3291 + _globals['_MATHFN']._serialized_end=3380 + _globals['_STRUCTOP']._serialized_start=3382 + _globals['_STRUCTOP']._serialized_end=3420 + _globals['_STRUCTFN']._serialized_start=3422 + _globals['_STRUCTFN']._serialized_end=3514 + _globals['_DICTGET']._serialized_start=3516 + _globals['_DICTGET']._serialized_end=3613 + _globals['_DICTOP']._serialized_start=3616 + _globals['_DICTOP']._serialized_end=3766 + _globals['_DICTFN']._serialized_start=3768 + _globals['_DICTFN']._serialized_end=3854 + _globals['_STRINGOP']._serialized_start=3857 + _globals['_STRINGOP']._serialized_end=4310 + _globals['_TIMEZONE']._serialized_start=4312 + _globals['_TIMEZONE']._serialized_end=4340 + _globals['_JSONDECODE']._serialized_start=4342 + _globals['_JSONDECODE']._serialized_end=4400 + _globals['_STRPTIME']._serialized_start=4402 + _globals['_STRPTIME']._serialized_end=4475 + _globals['_TOLOWER']._serialized_start=4477 + _globals['_TOLOWER']._serialized_end=4486 + _globals['_TOUPPER']._serialized_start=4488 + _globals['_TOUPPER']._serialized_end=4497 + _globals['_STARTSWITH']._serialized_start=4499 + _globals['_STARTSWITH']._serialized_end=4549 + _globals['_ENDSWITH']._serialized_start=4551 + _globals['_ENDSWITH']._serialized_end=4599 + _globals['_CONCAT']._serialized_start=4601 + _globals['_CONCAT']._serialized_end=4649 + _globals['_STRINGFN']._serialized_start=4651 + _globals['_STRINGFN']._serialized_end=4743 + _globals['_DATETIMEFN']._serialized_start=4745 + _globals['_DATETIMEFN']._serialized_end=4843 + _globals['_DATETIMEOP']._serialized_start=4846 + _globals['_DATETIMEOP']._serialized_end=5056 + _globals['_SINCE']._serialized_start=5058 + _globals['_SINCE']._serialized_end=5148 + _globals['_SINCEEPOCH']._serialized_start=5150 + _globals['_SINCEEPOCH']._serialized_end=5205 + _globals['_STRFTIME']._serialized_start=5207 + _globals['_STRFTIME']._serialized_end=5280 + _globals['_PART']._serialized_start=5282 + _globals['_PART']._serialized_end=5378 # @@protoc_insertion_point(module_scope) diff --git a/fennel/gen/expr_pb2.pyi b/fennel/gen/expr_pb2.pyi index 9c2911dd..9d6c2d73 100644 --- a/fennel/gen/expr_pb2.pyi +++ b/fennel/gen/expr_pb2.pyi @@ -110,6 +110,23 @@ MICROSECOND: TimeUnit.ValueType # 8 MILLISECOND: TimeUnit.ValueType # 9 global___TimeUnit = TimeUnit +@typing_extensions.final +class EvalContext(google.protobuf.message.Message): + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + NOW_COL_NAME_FIELD_NUMBER: builtins.int + now_col_name: builtins.str + def __init__( + self, + *, + now_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 WhichOneof(self, oneof_group: typing_extensions.Literal["_now_col_name", b"_now_col_name"]) -> typing_extensions.Literal["now_col_name"] | None: ... + +global___EvalContext = EvalContext + @typing_extensions.final class Expr(google.protobuf.message.Message): DESCRIPTOR: google.protobuf.descriptor.Descriptor @@ -131,6 +148,7 @@ class Expr(google.protobuf.message.Message): MAKE_STRUCT_FIELD_NUMBER: builtins.int FROM_EPOCH_FIELD_NUMBER: builtins.int VAR_FIELD_NUMBER: builtins.int + NOW_FIELD_NUMBER: builtins.int @property def ref(self) -> global___Ref: ... @property @@ -166,6 +184,8 @@ class Expr(google.protobuf.message.Message): def from_epoch(self) -> global___FromEpoch: ... @property def var(self) -> global___Var: ... + @property + def now(self) -> global___Now: ... def __init__( self, *, @@ -186,13 +206,24 @@ class Expr(google.protobuf.message.Message): make_struct: global___MakeStruct | None = ..., from_epoch: global___FromEpoch | None = ..., var: global___Var | None = ..., + now: global___Now | 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", "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", "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"] | 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: ... global___Expr = Expr +@typing_extensions.final +class Now(google.protobuf.message.Message): + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + def __init__( + self, + ) -> None: ... + +global___Now = Now + @typing_extensions.final class Var(google.protobuf.message.Message): DESCRIPTOR: google.protobuf.descriptor.Descriptor diff --git a/fennel/testing/query_engine.py b/fennel/testing/query_engine.py index 03ab7ad6..2cf6ce74 100644 --- a/fennel/testing/query_engine.py +++ b/fennel/testing/query_engine.py @@ -8,6 +8,7 @@ import fennel.datasets.datasets import fennel.gen.schema_pb2 as schema_proto +from fennel.expr.expr import EvalContext from fennel.featuresets import Extractor, Feature, Featureset, is_valid_feature from fennel.gen.featureset_pb2 import ( ExtractorType as ProtoExtractorType, @@ -22,6 +23,8 @@ cast_df_to_arrow_dtype, ) +NOW_COL_NAME = "__ts_col_name__" + class QueryEngine: """ @@ -170,7 +173,7 @@ def run_extractors( if extractor.extractor_type == ProtoExtractorType.EXPR: output = self._compute_expr_extractor( - extractor, intermediate_data + extractor, timestamps.copy(), intermediate_data ) self._check_schema_exceptions(output, dsschema, extractor.name) continue @@ -356,6 +359,7 @@ def _check_schema_exceptions( def _compute_expr_extractor( self, extractor: Extractor, + timestamps: pd.Series, intermediate_data: Dict[str, pd.Series], ) -> pd.Series: if len(extractor.outputs) != 1: @@ -371,8 +375,13 @@ def _compute_expr_extractor( } expr = extractor.expr input_schema = {f.name: f.dtype for f in extractor.inputs} + input_schema[NOW_COL_NAME] = datetime df = pd.DataFrame(input_features) - res = expr.eval(df, input_schema) # type: ignore + df[NOW_COL_NAME] = timestamps + res = expr.eval(df, input_schema, context=EvalContext(now_col_name=NOW_COL_NAME)) # type: ignore + output_dtype = expr.typeof(input_schema) # type: ignore + # Cast to correct arrow dtype after evaluating the expression + res = cast_col_to_arrow_dtype(res, get_datatype(output_dtype)) res.name = extractor.fqn_output_features()[0] intermediate_data[extractor.fqn_output_features()[0]] = res return res diff --git a/poetry.lock b/poetry.lock index c6f7ad6f..ec2e20b2 100644 --- a/poetry.lock +++ b/poetry.lock @@ -766,48 +766,48 @@ devel = ["colorama", "json-spec", "jsonschema", "pylint", "pytest", "pytest-benc [[package]] name = "fennel-data-lib" -version = "0.1.21" +version = "0.1.22" description = "" optional = false python-versions = ">=3.8" files = [ - {file = "fennel_data_lib-0.1.21-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:be633ae9295c346a72db2e667cfba6719621ea2aee6f7c6767684b1ad3e931cc"}, - {file = "fennel_data_lib-0.1.21-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:80512a481da6c459af43637d40093d64841068f7b33e7b53b37c495249b675b1"}, - {file = "fennel_data_lib-0.1.21-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:24118b8644dd4754630776ed0b9f08510efd3e0e81e59f10e3776c3565eda223"}, - {file = "fennel_data_lib-0.1.21-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a7379280c4d9d1651f91dedc828ae5f38f470b6e00c9386d0bc85ad233858f26"}, - {file = "fennel_data_lib-0.1.21-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2f3940eff028d9615cb178bb11d406d43f420554dd526f19a1d2d24ecb2386a4"}, - {file = "fennel_data_lib-0.1.21-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e70495692d523ee6594d8f86619954bdfea9c7a2fa531aede46034d96b17ad8"}, - {file = "fennel_data_lib-0.1.21-cp310-cp310-manylinux_2_34_x86_64.whl", hash = "sha256:03f5282d6920d10ccb15d12d29cd83ed1b62c3cc9d1a8bbf361a49bc96b951a6"}, - {file = "fennel_data_lib-0.1.21-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:69a496eece814baac05b4d7b4cac35e967a5fb04ce9fef17f8b073e032e5dfba"}, - {file = "fennel_data_lib-0.1.21-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c1ab35f93e7f1a8e8c3cf5daebbf28025f92f9797b0cd7677e0f9a77bae73514"}, - {file = "fennel_data_lib-0.1.21-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:35597a4f26ed6b2ebd3154b4f6dd346148085328a6dfdbad4a1614b253d444c8"}, - {file = "fennel_data_lib-0.1.21-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ecf53dcf5d79360120b8495a57477b4885b1fbd0fcf383dcde12c9fa19d127f9"}, - {file = "fennel_data_lib-0.1.21-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:014059ddf9f8a1110717bdf7aae449afb132bc6889979a2d7490f9d39ada46f1"}, - {file = "fennel_data_lib-0.1.21-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3a056b978667e5d9f25403ba5f85d7bfcd055f5655214f05741fbb90dee3359b"}, - {file = "fennel_data_lib-0.1.21-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:79f3d53007c445bbb535f131fcf31c575863fcf475ea48f313cb8157d77443f3"}, - {file = "fennel_data_lib-0.1.21-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd55011aa7ce01b585a3866baa6bef09557a16401cf9c4421ed69347e3646a9d"}, - {file = "fennel_data_lib-0.1.21-cp311-cp311-manylinux_2_34_x86_64.whl", hash = "sha256:a44af4e502a8ff4c8bdc9952e8c0a586e6c468e4b417d00d61154f695f142ded"}, - {file = "fennel_data_lib-0.1.21-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fb6ea76adde7ec3b9f6d393e675dfffe11baed6e3ca88edef6b57ca3158a244f"}, - {file = "fennel_data_lib-0.1.21-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6801459bdbc546bf2adf76b32bc74675c5cc27b4111bbc2e3b2e34bda0ad003e"}, - {file = "fennel_data_lib-0.1.21-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:8e06cfc288cf1f031082a157dcd8e96309e01178420660087959439b9bfff0f6"}, - {file = "fennel_data_lib-0.1.21-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69378c639d09b994d33b5037c28395b4babfa7868da6acaddc566760a5bae1d8"}, - {file = "fennel_data_lib-0.1.21-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e4b6cad57e9f09a1738f3bdd03f9d493f5f80f827f8cab56c655f02281418d97"}, - {file = "fennel_data_lib-0.1.21-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:deae17ccb4cd29906dd26d75f79581f6e8d1e19e7eaed2ed30e401fcb98bc6ef"}, - {file = "fennel_data_lib-0.1.21-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2e022d096154b32dca0ad0a81028a64571b3ea13fa171ca02bbd65fa904f7c14"}, - {file = "fennel_data_lib-0.1.21-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:71af0937e8f8d1edb46e0e9ed8d95ce989b4ca6763922f1776a32cd232aa789b"}, - {file = "fennel_data_lib-0.1.21-cp312-cp312-manylinux_2_34_x86_64.whl", hash = "sha256:b432ea48f3f5ae82b9de81ef27388c52a4f09324b552e0c6e5f462c650bde537"}, - {file = "fennel_data_lib-0.1.21-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:de34b96a2aca7e62742ff2cdb747d9500b341b4cd712003638761d348901491e"}, - {file = "fennel_data_lib-0.1.21-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:af2355aeb6e7028ae2796298f0c099095ea35a2240545c788a72618b4a590967"}, - {file = "fennel_data_lib-0.1.21-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:d80cea61199df9d8fab39467458f5523f2bd40684b160c4501afd7b13784baa0"}, - {file = "fennel_data_lib-0.1.21-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89b2ace5de48746cdd5aa51c002664e5bf7fc850a057b1323f4cc41d46cb0582"}, - {file = "fennel_data_lib-0.1.21-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4ccf2d82408c0e60f8c709ae858e9b96530150817e265f4a5505c5d9f6c307ed"}, - {file = "fennel_data_lib-0.1.21-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8bcd094536ad87da105fff5ceea2897d616683a0e31c588c879b366926df4a51"}, - {file = "fennel_data_lib-0.1.21-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d04ab4bd719a6e3983f0f6885c2d761bdde71e5eb7dd6990ee206c4da8e0be8b"}, - {file = "fennel_data_lib-0.1.21-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8b6f61838717217fb1d332d887eebebf24fb817423d3e10dfd4cb3c48a5a777"}, - {file = "fennel_data_lib-0.1.21-cp39-cp39-manylinux_2_34_x86_64.whl", hash = "sha256:9f88f74518e81605ebaebbdd933cbb1bb68f80d3e642b3dccb7ca5ddccfb00bd"}, - {file = "fennel_data_lib-0.1.21-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5fa3f086185eb9bdb6416c0ad1898f59c8a06fb6b49f43eb03233ca102f55faf"}, - {file = "fennel_data_lib-0.1.21-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:d24a04eef8f83ebcdfa795a623dc007bce687fca48fa53f7357e5a20fdeed152"}, - {file = "fennel_data_lib-0.1.21.tar.gz", hash = "sha256:53577e8a4affc227e1a972423fb6b2603b4e87c2c3b5d1a9e1b8eaccd28ebe4d"}, + {file = "fennel_data_lib-0.1.22-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:b7775ef71c464230741a025e3493b11be3da88930368f399dcab6ea190b7de51"}, + {file = "fennel_data_lib-0.1.22-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cdc29ecf35bbbd3119af11c3fc7a8b8f8ee76fe5acd233a210a97fc291580ee"}, + {file = "fennel_data_lib-0.1.22-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9d11e4d7a3cb2e70b05b6a3e65c149448547158f80558f336f40f062a00bf2d5"}, + {file = "fennel_data_lib-0.1.22-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ed37642f62f7e3bfe2b1adc0a8b6d875123e813a110e58a1892de7f8525b841"}, + {file = "fennel_data_lib-0.1.22-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8224b227c6f60b1e7aaa7dada4603b7257424b62c9fbc5a844efb086988fda29"}, + {file = "fennel_data_lib-0.1.22-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f25a088323472094b778bba23e4caac112a2218f6adde724642d15e4bcd5cef6"}, + {file = "fennel_data_lib-0.1.22-cp310-cp310-manylinux_2_34_x86_64.whl", hash = "sha256:89350b85476130eedcefbaa362664dd8264735becdcd7f53ff9daec358d63119"}, + {file = "fennel_data_lib-0.1.22-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:04298328368436585df47f5323f7b234b1ba1657e4203062e604cc95675ec017"}, + {file = "fennel_data_lib-0.1.22-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0f317a820c4c67690cf113478eb1bfe86e7000b7edb5fb88b7233926b513de50"}, + {file = "fennel_data_lib-0.1.22-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:d0c5f818e26c2ef3925f1da8bc5e9f5e56f9e179d13cf78338068991395fb4e5"}, + {file = "fennel_data_lib-0.1.22-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22426bb9e92ecdf9cdc69b2c1c476fdc2f92e7092590c4d24227f5f2d458892f"}, + {file = "fennel_data_lib-0.1.22-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b8a52eb2561b709eaee3de80cb9ee2ee6ff1de5c51e6a8a15eebf92a1957b241"}, + {file = "fennel_data_lib-0.1.22-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:617107f064042c4487f29550d683fc5375e3b14a803d9a2c0e8482e0cc2f4238"}, + {file = "fennel_data_lib-0.1.22-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:49bba1d2b9ec285ec682f3f251545498ad049a91c1d4407d8d48c5d922f9fe6e"}, + {file = "fennel_data_lib-0.1.22-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa37f7a77499720eb30fcb3179aaeda6b3e79ecce7009bc19abdb154499999d1"}, + {file = "fennel_data_lib-0.1.22-cp311-cp311-manylinux_2_34_x86_64.whl", hash = "sha256:94bcf382186d5e3e5aa9f67a4280c5fc6c575bf9b5e08e0c576e7534272d48e7"}, + {file = "fennel_data_lib-0.1.22-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:29f7b374576db9bd104d15b1335f5f7db08434aa7f10bcae7be6d28894849c0c"}, + {file = "fennel_data_lib-0.1.22-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a5c9a622d83200c46d19ee9a5db7511a9fc47bfbfade447b55933b30b6b98a74"}, + {file = "fennel_data_lib-0.1.22-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:dd76f9803357368c8ae1ca8d3af0f313f74d31cdf2e94240d67b8704a1a92cb0"}, + {file = "fennel_data_lib-0.1.22-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2639314b899eadfa2beb21c070bde1d995a02a62b6723544d5c751b5b60b99a8"}, + {file = "fennel_data_lib-0.1.22-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:611b3b118befd4b6b8a6628d7d381e369641fd88fa0728c366e45a90c28c7d9b"}, + {file = "fennel_data_lib-0.1.22-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:68d6584f937989d0b3c1587ce08576190176ad9e8b18b56562398f945c8d6bb9"}, + {file = "fennel_data_lib-0.1.22-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:feb3d8cf8ae6acfa27663e80ce8f71c32155bbbf8f6624621d8ff2d424794525"}, + {file = "fennel_data_lib-0.1.22-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:548a952665203ff9c85285d5eefa8cfb10a878f0d3ef7d2e631d6597649f5824"}, + {file = "fennel_data_lib-0.1.22-cp312-cp312-manylinux_2_34_x86_64.whl", hash = "sha256:afe170c2e4c4ea8ec0e1f9a7a74a406fefbaa8eb331ab2274f06e7a3141c4bcc"}, + {file = "fennel_data_lib-0.1.22-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:84dc38d1fd73ef26e1fe433d85a4f0a6411b3dde28b66d4553e84b99b5775f09"}, + {file = "fennel_data_lib-0.1.22-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:064f92604c56624a55f7d2edc930206ed56725570584ad618a3df4a33dd7a0a9"}, + {file = "fennel_data_lib-0.1.22-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:911a55b9739865f10d29a496023fff3e4ef1d4293656ccef394946d6eb2d65e1"}, + {file = "fennel_data_lib-0.1.22-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbf266cfe95fb3fa534d303b0ad4a315f407f4e0f241d1e608cc1abd3e647b06"}, + {file = "fennel_data_lib-0.1.22-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a63e5d8bd9b2ca9521dc40152b2190e1bb83b346a531f9d731e32e8ee5700081"}, + {file = "fennel_data_lib-0.1.22-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de58d19ae2a5079c0c698350a5f83d468bde7a379a5265c108138a385a00eb94"}, + {file = "fennel_data_lib-0.1.22-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b9a43626e495425ce764385cc5d58a5ac9ee4866eca965924a6d9f11508469b1"}, + {file = "fennel_data_lib-0.1.22-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a623c087c174bda0857aef638c18d130873c897c6935fc245d37e34f70f1b0c3"}, + {file = "fennel_data_lib-0.1.22-cp39-cp39-manylinux_2_34_x86_64.whl", hash = "sha256:703a389c4b748862b9bb71b22a3bd48aa37d0aecdd0c3c439881c818c9690b30"}, + {file = "fennel_data_lib-0.1.22-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9118c48de75a26be45c5fd3ad52fb61048d4cbafd7b83599d528fe8b526e0e1a"}, + {file = "fennel_data_lib-0.1.22-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2aedaec70a3abbf448a1a250e2b96ee98032da2040126c2116cb1ef3ed5882fa"}, + {file = "fennel_data_lib-0.1.22.tar.gz", hash = "sha256:7e27d220063fef16a284e28a890bbcbd7f3d2aea738ad6e495f0e9d6b3fba961"}, ] [[package]] @@ -3725,4 +3725,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "a1cef875ee95243b749253dbf87ceff13d3924bb9267ac0f6d47631a92b45076" +content-hash = "9f3156d7967bc35926ea8e6efc96ec0a8c720947804b7a4b5a76c82f67e36ee0" diff --git a/pyproject.toml b/pyproject.toml index 5936c8e1..5361c2fe 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "fennel-ai" -version = "1.5.32" +version = "1.5.33" 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.21" +fennel-data-lib = "0.1.22" pyarrow = "^14.0.2" [tool.poetry.dev-dependencies] @@ -49,14 +49,14 @@ build-backend = "poetry.core.masonry.api" # For local development, we use maturin to build the rust library -# [build-system] -# requires = ["maturin", "setuptools>=42", "wheel"] -# build-backend = "maturin" - -# [tool.maturin] -# name = "fennel_data_lib" -# sdist-directory = "python_package" -# manifest-path = "../server/fennel_data_lib/Cargo.toml" +#[build-system] +#requires = ["maturin", "setuptools>=42", "wheel"] +#build-backend = "maturin" +# +#[tool.maturin] +#name = "fennel_data_lib" +#sdist-directory = "python_package" +#manifest-path = "../server/fennel_data_lib/Cargo.toml" # inspired from - https://github.com/pypa/pip/blob/main/pyproject.toml