Repository: feast-dev/feast

Issue:
Entity from_yaml() initialises with value_type as name string representation instead of enum value
## Expected Behavior 

When loading an entity from `yaml`, one would expect `value_type` to be set to the enum value as described in the python class `__init__`:

```python
class Entity:
    ...
    def __init__(
        self,
        name: str,
        description: str,
        value_type: ValueType,
        labels: Optional[MutableMapping[str, str]] = None,
    ):
        self._name = name
        self._description = description
        self._value_type = value_type
...
```

## Current Behavior

Instead, it's initialised with `value_type` as the name of the type (e.g. `"STRING"` instead of `ValueType.STRING`).

For `FeatureTable`, the `dtype` is initialised to the python enum.

```python
>>> from feast import FeatureTable
>>> ft = FeatureTable.from_yaml("path/to/feature_table.yaml")
>>> ft.features[0].dtype
<ValueType.DOUBLE: 5>
```

## Steps to reproduce

```python
>>> from feast import Entity
>>> entity = Entity.from_yaml("path/to/entity.yaml")
>>> entity.value_type
'STRING'
```

### Specifications

- Version: 0.8.0
- Platform: Mac
- Subsystem:

## Possible Solution

In `Entity.from_proto()` we initialise with the `.name` value and explicitly ignore the type error:
```python
        entity = cls(
            name=entity_proto.spec.name,
            description=entity_proto.spec.description,
            value_type=ValueType(entity_proto.spec.value_type).name,  # type: ignore
            labels=entity_proto.spec.labels,
        )
```


Discussion:

Resolving patch:
diff --git a/sdk/python/feast/entity.py b/sdk/python/feast/entity.py
--- a/sdk/python/feast/entity.py
+++ b/sdk/python/feast/entity.py
@@ -53,11 +53,6 @@ def __eq__(self, other):
         if not isinstance(other, Entity):
             raise TypeError("Comparisons should only involve Entity class objects.")
 
-        if isinstance(self.value_type, int):
-            self.value_type = ValueType(self.value_type).name
-        if isinstance(other.value_type, int):
-            other.value_type = ValueType(other.value_type).name
-
         if (
             self.labels != other.labels
             or self.name != other.name
@@ -100,7 +95,7 @@ def description(self, description):
         self._description = description
 
     @property
-    def value_type(self):
+    def value_type(self) -> ValueType:
         """
         Returns the type of this entity
         """
@@ -200,7 +195,7 @@ def from_proto(cls, entity_proto: EntityV2Proto):
         entity = cls(
             name=entity_proto.spec.name,
             description=entity_proto.spec.description,
-            value_type=ValueType(entity_proto.spec.value_type).name,  # type: ignore
+            value_type=ValueType(entity_proto.spec.value_type),
             labels=entity_proto.spec.labels,
         )
 
@@ -221,13 +216,11 @@ def to_proto(self) -> EntityV2Proto:
             created_timestamp=self.created_timestamp,
             last_updated_timestamp=self.last_updated_timestamp,
         )
-        if isinstance(self.value_type, ValueType):
-            self.value_type = self.value_type.value
 
         spec = EntitySpecProto(
             name=self.name,
             description=self.description,
-            value_type=self.value_type,
+            value_type=self.value_type.value,
             labels=self.labels,
         )
 
@@ -268,13 +261,10 @@ def to_spec_proto(self) -> EntitySpecProto:
             EntitySpecV2 protobuf
         """
 
-        if isinstance(self.value_type, ValueType):
-            self.value_type = self.value_type.value
-
         spec = EntitySpecProto(
             name=self.name,
             description=self.description,
-            value_type=self.value_type,
+            value_type=self.value_type.value,
             labels=self.labels,
         )
 
diff --git a/sdk/python/feast/pyspark/launcher.py b/sdk/python/feast/pyspark/launcher.py
--- a/sdk/python/feast/pyspark/launcher.py
+++ b/sdk/python/feast/pyspark/launcher.py
@@ -151,7 +151,7 @@ def _feature_table_to_argument(
         "project": project,
         "name": feature_table.name,
         "entities": [
-            {"name": n, "type": client.get_entity(n, project=project).value_type}
+            {"name": n, "type": client.get_entity(n, project=project).value_type.name}
             for n in feature_table.entities
         ],
         "max_age": feature_table.max_age.ToSeconds() if feature_table.max_age else None,


Test patch:
diff --git a/sdk/python/tests/test_client.py b/sdk/python/tests/test_client.py
--- a/sdk/python/tests/test_client.py
+++ b/sdk/python/tests/test_client.py
@@ -385,7 +385,7 @@ def test_apply_entity_success(self, test_client):
         assert (
             len(entities) == 1
             and entity.name == "driver_car_id"
-            and entity.value_type == ValueType(ValueProto.ValueType.STRING).name
+            and entity.value_type == ValueType(ValueProto.ValueType.STRING)
             and entity.description == "Car driver id"
             and "team" in entity.labels
             and entity.labels["team"] == "matchmaking"