diff --git a/sdk/python/feast/field.py b/sdk/python/feast/field.py new file mode 100644 index 0000000000..498130e209 --- /dev/null +++ b/sdk/python/feast/field.py @@ -0,0 +1,84 @@ +# Copyright 2022 The Feast Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from feast.feature import Feature +from feast.protos.feast.core.Feature_pb2 import FeatureSpecV2 as FieldProto +from feast.types import FeastType, from_value_type + + +class Field: + """ + A Field represents a set of values with the same structure. + + Attributes: + name: The name of the field. + dtype: The type of the field, such as string or float. + """ + + name: str + dtype: FeastType + + def __init__( + self, *, name: str, dtype: FeastType, + ): + """ + Creates a Field object. + + Args: + name: The name of the field. + dtype: The type of the field, such as string or float. + """ + self.name = name + self.dtype = dtype + + def __eq__(self, other): + if self.name != other.name or self.dtype != other.dtype: + return False + return True + + def __hash__(self): + return hash((self.name, hash(self.dtype))) + + def __lt__(self, other): + return self.name < other.name + + def __repr__(self): + return f"{self.name}-{self.dtype}" + + def __str__(self): + return f"Field(name={self.name}, dtype={self.dtype})" + + def to_proto(self) -> FieldProto: + """Converts a Field object to its protobuf representation.""" + return FieldProto(name=self.name, value_type=self.dtype.to_value_type()) + + @classmethod + def from_proto(cls, field_proto: FieldProto): + """ + Creates a Field object from a protobuf representation. + + Args: + field_proto: FieldProto protobuf object + """ + return cls(name=field_proto.name, dtype=from_value_type(field_proto.value_type)) + + @classmethod + def from_feature(cls, feature: Feature): + """ + Creates a Field object from a Feature object. + + Args: + feature: Feature object to convert. + """ + return cls(name=feature.name, dtype=from_value_type(feature.dtype.value)) diff --git a/sdk/python/feast/types.py b/sdk/python/feast/types.py index 7542c73613..ebe02e31ad 100644 --- a/sdk/python/feast/types.py +++ b/sdk/python/feast/types.py @@ -46,6 +46,9 @@ def to_value_type(self) -> ValueTypeProto.Enum: """ raise NotImplementedError + def __hash__(self): + return hash(self.to_value_type()) + def __eq__(self, other): return self.to_value_type() == other.to_value_type() @@ -75,6 +78,9 @@ def to_value_type(self) -> ValueTypeProto.Enum: value_type_name = PRIMITIVE_FEAST_TYPES_TO_VALUE_TYPES[self.name] return ValueTypeProto.Enum.Value(value_type_name) + def __str__(self): + return PRIMITIVE_FEAST_TYPES_TO_STRING[self.name] + Invalid = PrimitiveFeastType.INVALID Bytes = PrimitiveFeastType.BYTES @@ -99,6 +105,18 @@ def to_value_type(self) -> ValueTypeProto.Enum: UnixTimestamp, ] +PRIMITIVE_FEAST_TYPES_TO_STRING = { + "INVALID": "Invalid", + "STRING": "String", + "BYTES": "Bytes", + "BOOL": "Bool", + "INT32": "Int32", + "INT64": "Int64", + "FLOAT32": "Float32", + "FLOAT64": "Float64", + "UNIX_TIMESTAMP": "UnixTimestamp", +} + class Array(ComplexFeastType): """ @@ -124,10 +142,14 @@ def to_value_type(self) -> int: value_type_list_name = value_type_name + "_LIST" return ValueTypeProto.Enum.Value(value_type_list_name) + def __str__(self): + return f"Array({self.base_type})" + + +FeastType = Union[ComplexFeastType, PrimitiveFeastType] + -VALUE_TYPES_TO_FEAST_TYPES: Dict[ - "ValueTypeProto.Enum", Union[ComplexFeastType, PrimitiveFeastType] -] = { +VALUE_TYPES_TO_FEAST_TYPES: Dict["ValueTypeProto.Enum", FeastType] = { ValueTypeProto.Enum.INVALID: Invalid, ValueTypeProto.Enum.BYTES: Bytes, ValueTypeProto.Enum.STRING: String, @@ -148,9 +170,7 @@ def to_value_type(self) -> int: } -def from_value_type( - value_type: ValueTypeProto.Enum, -) -> Union[ComplexFeastType, PrimitiveFeastType]: +def from_value_type(value_type: ValueTypeProto.Enum,) -> FeastType: """ Converts a ValueTypeProto.Enum to a Feast type.