Browse Source

Revert "chore(hybrid-cloud): Upgrade Pydantic to version 2.7 (#74770)"

This reverts commit 106b00a21c4ebe775d9ae1167032c6c6434e2552.

Co-authored-by: GabeVillalobos <5643012+GabeVillalobos@users.noreply.github.com>
getsentry-bot 7 months ago
parent
commit
2525223f87

+ 0 - 3
pyproject.toml

@@ -39,9 +39,6 @@ filterwarnings = [
 
 
   # pytest has not yet implemented the replacement for this yet
   # pytest has not yet implemented the replacement for this yet
   "ignore:The --looponfail command line argument.*",
   "ignore:The --looponfail command line argument.*",
-
-  # Temporarily disable deprecation warnings for pydantic while we upgrade it
-  "ignore::DeprecationWarning:pydantic.*",
 ]
 ]
 looponfailroots = ["src", "tests"]
 looponfailroots = ["src", "tests"]
 
 

+ 1 - 1
requirements-base.txt

@@ -45,7 +45,7 @@ python-rapidjson>=1.4
 psutil>=5.9.2
 psutil>=5.9.2
 psycopg2-binary>=2.9.9
 psycopg2-binary>=2.9.9
 PyJWT>=2.4.0
 PyJWT>=2.4.0
-pydantic>=2.5.0
+pydantic>=1.10.17,<2
 python-dateutil>=2.9.0
 python-dateutil>=2.9.0
 pymemcache
 pymemcache
 python-u2flib-server>=5.0.0
 python-u2flib-server>=5.0.0

+ 1 - 3
requirements-dev-frozen.txt

@@ -7,7 +7,6 @@
 --index-url https://pypi.devinfra.sentry.io/simple
 --index-url https://pypi.devinfra.sentry.io/simple
 
 
 amqp==5.2.0
 amqp==5.2.0
-annotated-types==0.7.0
 anyio==3.7.1
 anyio==3.7.1
 asgiref==3.7.2
 asgiref==3.7.2
 attrs==23.1.0
 attrs==23.1.0
@@ -138,8 +137,7 @@ pyasn1-modules==0.2.4
 pycodestyle==2.11.0
 pycodestyle==2.11.0
 pycountry==17.5.14
 pycountry==17.5.14
 pycparser==2.21
 pycparser==2.21
-pydantic==2.7.4
-pydantic-core==2.18.4
+pydantic==1.10.17
 pyflakes==3.2.0
 pyflakes==3.2.0
 pyjwt==2.4.0
 pyjwt==2.4.0
 pymemcache==4.0.0
 pymemcache==4.0.0

+ 1 - 3
requirements-frozen.txt

@@ -7,7 +7,6 @@
 --index-url https://pypi.devinfra.sentry.io/simple
 --index-url https://pypi.devinfra.sentry.io/simple
 
 
 amqp==5.2.0
 amqp==5.2.0
-annotated-types==0.7.0
 anyio==3.7.1
 anyio==3.7.1
 asgiref==3.7.2
 asgiref==3.7.2
 attrs==23.1.0
 attrs==23.1.0
@@ -97,8 +96,7 @@ pyasn1==0.4.5
 pyasn1-modules==0.2.4
 pyasn1-modules==0.2.4
 pycountry==17.5.14
 pycountry==17.5.14
 pycparser==2.21
 pycparser==2.21
-pydantic==2.7.4
-pydantic-core==2.18.4
+pydantic==1.10.17
 pyjwt==2.4.0
 pyjwt==2.4.0
 pymemcache==4.0.0
 pymemcache==4.0.0
 pyparsing==3.0.9
 pyparsing==3.0.9

+ 1 - 1
src/sentry/autofix/utils.py

@@ -1,11 +1,11 @@
 import datetime
 import datetime
 import enum
 import enum
+from typing import TypedDict
 
 
 import orjson
 import orjson
 import requests
 import requests
 from django.conf import settings
 from django.conf import settings
 from pydantic import BaseModel
 from pydantic import BaseModel
-from typing_extensions import TypedDict
 
 
 from sentry.integrations.utils.code_mapping import get_sorted_code_mapping_configs
 from sentry.integrations.utils.code_mapping import get_sorted_code_mapping_configs
 from sentry.models.project import Project
 from sentry.models.project import Project

+ 4 - 6
src/sentry/hybridcloud/rpc/__init__.py

@@ -11,7 +11,6 @@ from typing import Any, Generic, Protocol, Self, TypeVar, cast
 import pydantic
 import pydantic
 from django.db import router, transaction
 from django.db import router, transaction
 from django.db.models import Model
 from django.db.models import Model
-from pydantic import ConfigDict
 
 
 from sentry.silo.base import SiloMode
 from sentry.silo.base import SiloMode
 from sentry.utils.env import in_test_environment
 from sentry.utils.env import in_test_environment
@@ -44,14 +43,13 @@ class ValueEqualityEnum(Enum):
 class RpcModel(pydantic.BaseModel):
 class RpcModel(pydantic.BaseModel):
     """A serializable object that may be part of an RPC schema."""
     """A serializable object that may be part of an RPC schema."""
 
 
-    # TODO(Hybrid-Cloud): Remove number coercion after pydantic V2 stabilized
-    model_config = ConfigDict(
-        from_attributes=True, use_enum_values=True, coerce_numbers_to_str=True
-    )
+    class Config:
+        orm_mode = True
+        use_enum_values = True
 
 
     @classmethod
     @classmethod
     def get_field_names(cls) -> Iterable[str]:
     def get_field_names(cls) -> Iterable[str]:
-        return iter(cls.model_fields.keys())
+        return iter(cls.__fields__.keys())
 
 
     @classmethod
     @classmethod
     def serialize_by_field_name(
     def serialize_by_field_name(

+ 1 - 5
src/sentry/hybridcloud/rpc/sig.py

@@ -7,7 +7,6 @@ from typing import Any
 
 
 import pydantic
 import pydantic
 from django.utils.functional import LazyObject
 from django.utils.functional import LazyObject
-from pydantic import ConfigDict
 
 
 from sentry.hybridcloud.rpc import ArgumentDict
 from sentry.hybridcloud.rpc import ArgumentDict
 
 
@@ -82,10 +81,7 @@ class SerializableFunctionSignature:
         if self.is_instance_method:
         if self.is_instance_method:
             parameters = parameters[1:]  # exclude `self` argument
             parameters = parameters[1:]  # exclude `self` argument
         field_definitions = {p.name: create_field(p) for p in parameters}
         field_definitions = {p.name: create_field(p) for p in parameters}
-
-        # TODO(Hybrid-Cloud): Remove number coercion after pydantic V2 stabilized
-        config = ConfigDict(coerce_numbers_to_str=True)
-        return pydantic.create_model(model_name, __config__=config, **field_definitions)  # type: ignore[call-overload]
+        return pydantic.create_model(model_name, **field_definitions)  # type: ignore[call-overload]
 
 
     _RETURN_MODEL_ATTR = "value"
     _RETURN_MODEL_ATTR = "value"
 
 

+ 2 - 3
src/sentry/types/region.py

@@ -8,8 +8,8 @@ from urllib.parse import urljoin
 import sentry_sdk
 import sentry_sdk
 from django.conf import settings
 from django.conf import settings
 from django.http import HttpRequest
 from django.http import HttpRequest
-from pydantic import TypeAdapter
 from pydantic.dataclasses import dataclass
 from pydantic.dataclasses import dataclass
+from pydantic.tools import parse_obj_as
 
 
 from sentry import options
 from sentry import options
 from sentry.silo.base import SiloMode, SingleProcessSiloModeState, control_silo_function
 from sentry.silo.base import SiloMode, SingleProcessSiloModeState, control_silo_function
@@ -151,8 +151,7 @@ class RegionDirectory:
 def _parse_raw_config(region_config: Any) -> Iterable[Region]:
 def _parse_raw_config(region_config: Any) -> Iterable[Region]:
     if isinstance(region_config, (str, bytes)):
     if isinstance(region_config, (str, bytes)):
         json_config_values = json.loads(region_config)
         json_config_values = json.loads(region_config)
-        adapter = TypeAdapter(list[Region])
-        config_values = adapter.validate_python(json_config_values)
+        config_values = parse_obj_as(list[Region], json_config_values)
     else:
     else:
         config_values = region_config
         config_values = region_config
 
 

+ 1 - 1
src/sentry/users/services/user/serial.py

@@ -36,7 +36,7 @@ def serialize_generic_user(user: Any) -> RpcUser | None:
 def _serialize_from_user_fields(user: User) -> dict[str, Any]:
 def _serialize_from_user_fields(user: User) -> dict[str, Any]:
     args = {
     args = {
         field_name: getattr(user, field_name)
         field_name: getattr(user, field_name)
-        for field_name in RpcUserProfile.model_fields
+        for field_name in RpcUserProfile.__fields__
         if hasattr(user, field_name)
         if hasattr(user, field_name)
     }
     }
     args["pk"] = user.pk
     args["pk"] = user.pk

+ 1 - 8
tests/sentry/api/endpoints/test_organization_sdk_updates.py

@@ -2,7 +2,6 @@ from unittest import mock
 
 
 import pytest
 import pytest
 from django.urls import reverse
 from django.urls import reverse
-from pydantic import PydanticDeprecatedSince20
 
 
 from sentry.sdk_updates import SdkIndexState
 from sentry.sdk_updates import SdkIndexState
 from sentry.testutils.cases import APITestCase, SnubaTestCase
 from sentry.testutils.cases import APITestCase, SnubaTestCase
@@ -189,14 +188,8 @@ class OrganizationSdkUpdates(APITestCase, SnubaTestCase):
         update_suggestions = response.data
         update_suggestions = response.data
         assert len(update_suggestions) == 0
         assert len(update_suggestions) == 0
 
 
-        # TODO(Gabe): Temporary kludge to allow this to pass while pydantic
-        # deprecation warnings are active.
-        filtered_warnings = [
-            info for info in warninfo if not isinstance(info.message, PydanticDeprecatedSince20)
-        ]
-
         # until it is turned into an error, we'll get a warning about parsing an invalid version
         # until it is turned into an error, we'll get a warning about parsing an invalid version
-        (warning,) = filtered_warnings
+        (warning,) = warninfo
         assert isinstance(warning.message, DeprecationWarning)
         assert isinstance(warning.message, DeprecationWarning)
         (warn_msg,) = warning.message.args
         (warn_msg,) = warning.message.args
         assert (
         assert (

Some files were not shown because too many files changed in this diff