Skip to content

Commit 4864252

Browse files
feat: Add Feast types in preparation for changing type system (#2475)
* Fix import Signed-off-by: Felix Wang <wangfelix98@gmail.com> * Add types Signed-off-by: Felix Wang <wangfelix98@gmail.com> * Fix types Signed-off-by: Felix Wang <wangfelix98@gmail.com> * Test type errors Signed-off-by: Felix Wang <wangfelix98@gmail.com> * Rename FeastType to ComplexFeastType Signed-off-by: Felix Wang <wangfelix98@gmail.com>
1 parent 514666f commit 4864252

File tree

3 files changed

+142
-2
lines changed

3 files changed

+142
-2
lines changed

sdk/python/feast/feature.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
from typing import Dict, Optional
1616

1717
from feast.protos.feast.core.Feature_pb2 import FeatureSpecV2 as FeatureSpecProto
18-
from feast.protos.feast.types import Value_pb2 as ValueTypeProto
18+
from feast.protos.feast.types.Value_pb2 import ValueType as ValueTypeProto
1919
from feast.value_type import ValueType
2020

2121

@@ -88,7 +88,7 @@ def to_proto(self) -> FeatureSpecProto:
8888
Returns:
8989
A FeatureSpecProto protobuf.
9090
"""
91-
value_type = ValueTypeProto.ValueType.Enum.Value(self.dtype.name)
91+
value_type = ValueTypeProto.Enum.Value(self.dtype.name)
9292

9393
return FeatureSpecProto(
9494
name=self.name, value_type=value_type, labels=self.labels,

sdk/python/feast/types.py

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
# Copyright 2022 The Feast Authors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
from abc import ABC, abstractmethod
15+
from enum import Enum
16+
from typing import Union
17+
18+
from feast.protos.feast.types.Value_pb2 import ValueType as ValueTypeProto
19+
20+
PRIMITIVE_FEAST_TYPES_TO_VALUE_TYPES = {
21+
"INVALID": "INVALID",
22+
"STRING": "STRING",
23+
"BYTES": "BYTES",
24+
"BOOL": "BOOL",
25+
"INT32": "INT32",
26+
"INT64": "INT64",
27+
"FLOAT32": "FLOAT",
28+
"FLOAT64": "DOUBLE",
29+
"UNIX_TIMESTAMP": "UNIX_TIMESTAMP",
30+
}
31+
32+
33+
class ComplexFeastType(ABC):
34+
"""
35+
A ComplexFeastType represents a structured type that is recognized by Feast.
36+
"""
37+
38+
def __init__(self):
39+
"""Creates a ComplexFeastType object."""
40+
pass
41+
42+
@abstractmethod
43+
def to_int(self) -> int:
44+
"""
45+
Converts a ComplexFeastType object to the appropriate int value corresponding to
46+
the correct ValueTypeProto.Enum value.
47+
"""
48+
raise NotImplementedError
49+
50+
51+
class PrimitiveFeastType(Enum):
52+
"""
53+
A PrimitiveFeastType represents a primitive type in Feast.
54+
"""
55+
56+
INVALID = 0
57+
BYTES = 1
58+
STRING = 2
59+
INT32 = 3
60+
INT64 = 4
61+
FLOAT32 = 5
62+
FLOAT64 = 6
63+
BOOL = 7
64+
UNIX_TIMESTAMP = 8
65+
66+
def to_int(self) -> int:
67+
value_type_name = PRIMITIVE_FEAST_TYPES_TO_VALUE_TYPES[self.name]
68+
return ValueTypeProto.Enum.Value(value_type_name)
69+
70+
71+
Invalid = PrimitiveFeastType.INVALID
72+
Bytes = PrimitiveFeastType.BYTES
73+
String = PrimitiveFeastType.STRING
74+
Bool = PrimitiveFeastType.BOOL
75+
Int32 = PrimitiveFeastType.INT32
76+
Int64 = PrimitiveFeastType.INT64
77+
Float32 = PrimitiveFeastType.FLOAT32
78+
Float64 = PrimitiveFeastType.FLOAT64
79+
UnixTimestamp = PrimitiveFeastType.UNIX_TIMESTAMP
80+
81+
82+
SUPPORTED_BASE_TYPES = [
83+
Invalid,
84+
String,
85+
Bytes,
86+
Bool,
87+
Int32,
88+
Int64,
89+
Float32,
90+
Float64,
91+
UnixTimestamp,
92+
]
93+
94+
95+
class Array(ComplexFeastType):
96+
"""
97+
An Array represents a list of types.
98+
99+
Attributes:
100+
base_type: The base type of the array.
101+
"""
102+
103+
base_type: Union[PrimitiveFeastType, ComplexFeastType]
104+
105+
def __init__(self, base_type: Union[PrimitiveFeastType, ComplexFeastType]):
106+
if base_type not in SUPPORTED_BASE_TYPES:
107+
raise ValueError(
108+
f"Type {type(base_type)} is currently not supported as a base type for Array."
109+
)
110+
111+
self.base_type = base_type
112+
113+
def to_int(self) -> int:
114+
assert isinstance(self.base_type, PrimitiveFeastType)
115+
value_type_name = PRIMITIVE_FEAST_TYPES_TO_VALUE_TYPES[self.base_type.name]
116+
value_type_list_name = value_type_name + "_LIST"
117+
return ValueTypeProto.Enum.Value(value_type_list_name)
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import pytest
2+
3+
from feast.protos.feast.types.Value_pb2 import ValueType as ValueTypeProto
4+
from feast.types import Array, Float32, String
5+
6+
7+
def test_primitive_feast_type():
8+
assert String.to_int() == ValueTypeProto.Enum.Value("STRING")
9+
assert Float32.to_int() == ValueTypeProto.Enum.Value("FLOAT")
10+
11+
12+
def test_array_feast_type():
13+
array_float_32 = Array(Float32)
14+
assert array_float_32.to_int() == ValueTypeProto.Enum.Value("FLOAT_LIST")
15+
16+
array_string = Array(String)
17+
assert array_string.to_int() == ValueTypeProto.Enum.Value("STRING_LIST")
18+
19+
with pytest.raises(ValueError):
20+
_ = Array(Array)
21+
22+
with pytest.raises(ValueError):
23+
_ = Array(Array(String))

0 commit comments

Comments
 (0)