Repository: Flagsmith/flagsmith-engine (language: python)

Issue:
Unable to identify user with a trait that has the value `"Nan"`
**Describe the bug**

Setting a trait to a string of `"Nan"` when identifying a user causes a 502 error in the Edge API and will cause the detail view of the identity to fail to load in the Flagsmith dashboard. 

**To Reproduce**

```bash
curl --location 'https://edge.api.flagsmith.com/api/v1/identities' \
--header 'Content-Type: application/json' \
--header 'X-Environment-Key: <ENV_KEY>' \
--data '{
    "identifier": "identity",
    "traits": [
        {
            "trait_key": "my_trait",
            "trait_value": "Nan"
        }
    ]
}'
```

**Expected behavior**

 1. The trait is stored as a string and a successful response is returned from the Edge API
 2. The identity detail page loads in the Flagsmith dashboard and shows the trait as a string

**Screenshots**

N/a

**How are you running Flagsmith?**

- [ ] Self Hosted with Docker
- [ ] Self Hosted with Kubernetes
- [x] SaaS at flagsmith.com
- [ ] Some other way

**Additional context**

A quick fix here is to set the trait value to e.g. `"Nan_"`



Discussion / hints:
Seems like this is some very odd behaviour from pydantic. Here is a minimal script to reproduce the issue: 

```python
import typing
from pydantic import BaseModel


class MyModel(BaseModel):
    foo: typing.Union[float, str]


o = MyModel.parse_obj({"foo": "Nan"})

assert o.foo == "Nan"
```

This will throw an `AssertionError`

Fix patch:
diff --git a/flag_engine/identities/traits/types.py b/flag_engine/identities/traits/types.py
index f5de361..92e1633 100644
--- a/flag_engine/identities/traits/types.py
+++ b/flag_engine/identities/traits/types.py
@@ -1,12 +1,12 @@
 from typing import Union
 
-from pydantic import constr
+from pydantic.types import confloat, constr
 
 from flag_engine.identities.traits.constants import TRAIT_STRING_VALUE_MAX_LENGTH
 
 TraitValue = Union[
     None,
-    float,
+    confloat(allow_inf_nan=False),
     int,
     bool,
     constr(max_length=TRAIT_STRING_VALUE_MAX_LENGTH),


Test patch:
diff --git a/tests/unit/identities/test_identities_models.py b/tests/unit/identities/test_identities_models.py
index 11a15dd..426fb7c 100644
--- a/tests/unit/identities/test_identities_models.py
+++ b/tests/unit/identities/test_identities_models.py
@@ -202,3 +202,18 @@ def test_trait_model__deserialize__expected_trait_value(
     # Then
     assert isinstance(result.trait_value, type(expected_result))
     assert result.trait_value == expected_result
+
+
+def test_identity_model__deserialize__handles_nan():
+    # When
+    result = IdentityModel.parse_obj(
+        {
+            "identifier": "identity",
+            "environment_api_key": "api-key",
+            "identity_traits": [{"trait_key": "nan_trait", "trait_value": "Nan"}],
+        }
+    )
+
+    # Then
+    assert result
+    assert result.identity_traits[0].trait_value == "Nan"