From 11e761e93d412f5a955af3eb27cf3ec0333fa557 Mon Sep 17 00:00:00 2001
From: spencer <swilbur@usgs.gov>
Date: Wed, 14 Feb 2024 16:04:44 -0700
Subject: [PATCH] Updated the fastapi package which required a few changes to
 the file pydantic_utcdatetime.py module. The module now contains a workaround
 to deal with the way pydantic manages the UTCDateTime string. This is a new
 issue that was caused by updating to fastapi version 0.109.2.

---
 geomagio/pydantic_utcdatetime.py | 36 +++++++++++++++++++++++++++-----
 poetry.lock                      | 26 +++++++++++------------
 pyproject.toml                   |  2 +-
 3 files changed, 44 insertions(+), 20 deletions(-)

diff --git a/geomagio/pydantic_utcdatetime.py b/geomagio/pydantic_utcdatetime.py
index 52ce67e26..9e852d2a9 100644
--- a/geomagio/pydantic_utcdatetime.py
+++ b/geomagio/pydantic_utcdatetime.py
@@ -46,12 +46,38 @@ def format_utcdatetime(o: UTCDateTime) -> str:
 
 
 def parse_utcdatetime(
-    value: Union[datetime, float, int, str, UTCDateTime]
+    value: Union[datetime, float, int, str, UTCDateTime, Dict]
 ) -> UTCDateTime:
-    try:
-        return UTCDateTime(value)
-    except:
-        raise UTCDateTimeError()
+    if isinstance(value, UTCDateTime):
+        # If the value is already a UTCDateTime, return it directly
+        return value
+    elif isinstance(value, dict):
+        # Handle the nanosecond dictionary format
+        try:
+            # Assuming the dictionary format is something like {'_UTCDateTime__ns': 1598918401000000000}
+            ns = value.get("_UTCDateTime__ns")
+            if ns is not None:
+                return UTCDateTime(ns / 1e9)  # Convert nanoseconds to seconds
+        except Exception as e:
+            raise UTCDateTimeError() from e
+    else:
+        # Handle other formats (datetime, float, int, str)
+        try:
+            return UTCDateTime(value)
+        except Exception:
+            raise UTCDateTimeError()
+
+    raise UTCDateTimeError()  # Raise an error if none of the above conditions are met
+
+
+# Code below is what was used to parse UTCDateTime value for pydantic before version 109 break.
+# def parse_utcdatetime(
+#     value: Union[datetime, float, int, str, UTCDateTime]
+# ) -> UTCDateTime:
+#     try:
+#         return UTCDateTime(value)
+#     except:
+#         raise UTCDateTimeError()
 
 
 register_custom_pydantic_type(
diff --git a/poetry.lock b/poetry.lock
index 0c7cd9538..ec80ae5b2 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -648,25 +648,23 @@ test = ["pytest (>=6)"]
 
 [[package]]
 name = "fastapi"
-version = "0.1.17"
+version = "0.109.2"
 description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production"
 category = "main"
 optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.8"
 files = [
-    {file = "fastapi-0.1.17-py3-none-any.whl", hash = "sha256:a6aaad2f60684477480ac9d7a1c95e67f4696a722f184db467494bfdd5b8f29d"},
-    {file = "fastapi-0.1.17.tar.gz", hash = "sha256:a9a9b6cc32c38bab27a6549b94c44a30c70b485bc789d03de3aa8725f3394be5"},
+    {file = "fastapi-0.109.2-py3-none-any.whl", hash = "sha256:2c9bab24667293b501cad8dd388c05240c850b58ec5876ee3283c47d6e1e3a4d"},
+    {file = "fastapi-0.109.2.tar.gz", hash = "sha256:f3817eac96fe4f65a2ebb4baa000f394e55f5fccdaf7f75250804bc58f354f73"},
 ]
 
 [package.dependencies]
-pydantic = ">=0.17"
-starlette = ">=0.9.7"
+pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0"
+starlette = ">=0.36.3,<0.37.0"
+typing-extensions = ">=4.8.0"
 
 [package.extras]
-all = ["aiofiles", "email_validator", "graphene", "itsdangerous", "jinja2", "python-multipart", "pyyaml", "requests", "ujson", "ujson", "uvicorn"]
-dev = ["passlib[bcrypt]", "pyjwt"]
-doc = ["markdown-include", "mkdocs", "mkdocs-material"]
-test = ["black", "email_validator", "isort", "mypy", "pytest (>=4.0.0)", "pytest-cov", "requests"]
+all = ["email-validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.7)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"]
 
 [[package]]
 name = "fonttools"
@@ -2281,14 +2279,14 @@ SQLAlchemy = ">=0.9.0"
 
 [[package]]
 name = "starlette"
-version = "0.37.1"
+version = "0.36.3"
 description = "The little ASGI library that shines."
 category = "main"
 optional = false
 python-versions = ">=3.8"
 files = [
-    {file = "starlette-0.37.1-py3-none-any.whl", hash = "sha256:92a816002d4e8c552477b089520e3085bb632e854eb32cef99acb6f6f7830b69"},
-    {file = "starlette-0.37.1.tar.gz", hash = "sha256:345cfd562236b557e76a045715ac66fdc355a1e7e617b087834a76a87dcc6533"},
+    {file = "starlette-0.36.3-py3-none-any.whl", hash = "sha256:13d429aa93a61dc40bf503e8c801db1f1bca3dc706b10ef2434a36123568f044"},
+    {file = "starlette-0.36.3.tar.gz", hash = "sha256:90a671733cfb35771d8cc605e0b679d23b992f8dcfad48cc60b38cb29aeb7080"},
 ]
 
 [package.dependencies]
@@ -2651,4 +2649,4 @@ pycurl = ["pycurl"]
 [metadata]
 lock-version = "2.0"
 python-versions = ">=3.8,<=3.11.*"
-content-hash = "6208092fdaca4822a9eea892ecf20f293c1330220a4877027a4f570de5b43c4d"
+content-hash = "c787881982d4b282c5878f8c62bfadea9734c093e98b8b17278afb70263284fd"
diff --git a/pyproject.toml b/pyproject.toml
index 88f20f731..8e58016d5 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -36,7 +36,7 @@ alembic = "^1.8.1"
 Authlib = "^1.1.0"
 cryptography = "^42.0.0"
 databases = {extras = ["mysql", "sqlite"], version = "^0.6.1"}
-fastapi = "^0.1.0"
+fastapi = "^0.109.1"
 gunicorn = "^20.1.0"
 httpx = "0.23.0"
 # 2022-10-24 pin sqlalchemy to 1.4.41 for now
-- 
GitLab