Skip to content

Commit ebad618

Browse files
authored
import pydantic objects from the _pydantic_compat module (#17667)
This PR changes `from pydantic import BaseModel` to `from synapse._pydantic_compat import BaseModel` (as well as `constr`, `conbytes`, `conint`, `confloat`). It allows `check_pydantic_models.py` to mock those pydantic objects only in the synapse module, and not interfere with pydantic objects in external dependencies. This should solve the CI problems for #17144, which breaks because `check_pydantic_models.py` patches pydantic models from [scim2-models](https://scim2-models.readthedocs.io/). /cc @DMRobertson @gotmax23 fixes #17659 ### Pull Request Checklist <!-- Please read https://element-hq.github.io/synapse/latest/development/contributing_guide.html before submitting your pull request --> * [x] Pull request is based on the develop branch * [x] Pull request includes a [changelog file](https://element-hq.github.io/synapse/latest/development/contributing_guide.html#changelog). The entry should: - Be a short description of your change which makes sense to users. "Fixed a bug that prevented receiving messages from other servers." instead of "Moved X method from `EventStore` to `EventWorkerStore`.". - Use markdown where necessary, mostly for `code blocks`. - End with either a period (.) or an exclamation mark (!). - Start with a capital letter. - Feel free to credit yourself, by adding a sentence "Contributed by @github_username." or "Contributed by [Your Name]." to the end of the entry. * [x] [Code style](https://element-hq.github.io/synapse/latest/code_style.html) is correct (run the [linters](https://element-hq.github.io/synapse/latest/development/contributing_guide.html#run-the-linters))
1 parent 16af80b commit ebad618

File tree

18 files changed

+126
-161
lines changed

18 files changed

+126
-161
lines changed

changelog.d/17667.misc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Import pydantic objects from the `_pydantic_compat` module.
2+
3+
This allows `check_pydantic_models.py` to mock those pydantic objects
4+
only in the synapse module, and not interfere with pydantic objects in
5+
external dependencies.

scripts-dev/check_pydantic_models.py

Lines changed: 15 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@
4545
import unittest.mock
4646
from contextlib import contextmanager
4747
from typing import (
48-
TYPE_CHECKING,
4948
Any,
5049
Callable,
5150
Dict,
@@ -57,30 +56,17 @@
5756
)
5857

5958
from parameterized import parameterized
60-
61-
from synapse._pydantic_compat import HAS_PYDANTIC_V2
62-
63-
if TYPE_CHECKING or HAS_PYDANTIC_V2:
64-
from pydantic.v1 import (
65-
BaseModel as PydanticBaseModel,
66-
conbytes,
67-
confloat,
68-
conint,
69-
constr,
70-
)
71-
from pydantic.v1.typing import get_args
72-
else:
73-
from pydantic import (
74-
BaseModel as PydanticBaseModel,
75-
conbytes,
76-
confloat,
77-
conint,
78-
constr,
79-
)
80-
from pydantic.typing import get_args
81-
8259
from typing_extensions import ParamSpec
8360

61+
from synapse._pydantic_compat import (
62+
BaseModel as PydanticBaseModel,
63+
conbytes,
64+
confloat,
65+
conint,
66+
constr,
67+
get_args,
68+
)
69+
8470
logger = logging.getLogger(__name__)
8571

8672
CONSTRAINED_TYPE_FACTORIES_WITH_STRICT_FLAG: List[Callable] = [
@@ -183,22 +169,16 @@ def monkeypatch_pydantic() -> Generator[None, None, None]:
183169
# Most Synapse code ought to import the patched objects directly from
184170
# `pydantic`. But we also patch their containing modules `pydantic.main` and
185171
# `pydantic.types` for completeness.
186-
patch_basemodel1 = unittest.mock.patch(
187-
"pydantic.BaseModel", new=PatchedBaseModel
188-
)
189-
patch_basemodel2 = unittest.mock.patch(
190-
"pydantic.main.BaseModel", new=PatchedBaseModel
172+
patch_basemodel = unittest.mock.patch(
173+
"synapse._pydantic_compat.BaseModel", new=PatchedBaseModel
191174
)
192-
patches.enter_context(patch_basemodel1)
193-
patches.enter_context(patch_basemodel2)
175+
patches.enter_context(patch_basemodel)
194176
for factory in CONSTRAINED_TYPE_FACTORIES_WITH_STRICT_FLAG:
195177
wrapper: Callable = make_wrapper(factory)
196-
patch1 = unittest.mock.patch(f"pydantic.{factory.__name__}", new=wrapper)
197-
patch2 = unittest.mock.patch(
198-
f"pydantic.types.{factory.__name__}", new=wrapper
178+
patch = unittest.mock.patch(
179+
f"synapse._pydantic_compat.{factory.__name__}", new=wrapper
199180
)
200-
patches.enter_context(patch1)
201-
patches.enter_context(patch2)
181+
patches.enter_context(patch)
202182
yield
203183

204184

synapse/_pydantic_compat.py

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
#
2020
#
2121

22+
from typing import TYPE_CHECKING
23+
2224
from packaging.version import Version
2325

2426
try:
@@ -30,4 +32,64 @@
3032

3133
HAS_PYDANTIC_V2: bool = Version(pydantic_version).major == 2
3234

33-
__all__ = ("HAS_PYDANTIC_V2",)
35+
if TYPE_CHECKING or HAS_PYDANTIC_V2:
36+
from pydantic.v1 import (
37+
BaseModel,
38+
Extra,
39+
Field,
40+
MissingError,
41+
PydanticValueError,
42+
StrictBool,
43+
StrictInt,
44+
StrictStr,
45+
ValidationError,
46+
conbytes,
47+
confloat,
48+
conint,
49+
constr,
50+
parse_obj_as,
51+
validator,
52+
)
53+
from pydantic.v1.error_wrappers import ErrorWrapper
54+
from pydantic.v1.typing import get_args
55+
else:
56+
from pydantic import (
57+
BaseModel,
58+
Extra,
59+
Field,
60+
MissingError,
61+
PydanticValueError,
62+
StrictBool,
63+
StrictInt,
64+
StrictStr,
65+
ValidationError,
66+
conbytes,
67+
confloat,
68+
conint,
69+
constr,
70+
parse_obj_as,
71+
validator,
72+
)
73+
from pydantic.error_wrappers import ErrorWrapper
74+
from pydantic.typing import get_args
75+
76+
__all__ = (
77+
"HAS_PYDANTIC_V2",
78+
"BaseModel",
79+
"constr",
80+
"conbytes",
81+
"conint",
82+
"confloat",
83+
"ErrorWrapper",
84+
"Extra",
85+
"Field",
86+
"get_args",
87+
"MissingError",
88+
"parse_obj_as",
89+
"PydanticValueError",
90+
"StrictBool",
91+
"StrictInt",
92+
"StrictStr",
93+
"ValidationError",
94+
"validator",
95+
)

synapse/config/_util.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,11 @@
1818
# [This file includes modifications made by New Vector Limited]
1919
#
2020
#
21-
from typing import TYPE_CHECKING, Any, Dict, Type, TypeVar
21+
from typing import Any, Dict, Type, TypeVar
2222

2323
import jsonschema
2424

25-
from synapse._pydantic_compat import HAS_PYDANTIC_V2
26-
27-
if TYPE_CHECKING or HAS_PYDANTIC_V2:
28-
from pydantic.v1 import BaseModel, ValidationError, parse_obj_as
29-
else:
30-
from pydantic import BaseModel, ValidationError, parse_obj_as
31-
25+
from synapse._pydantic_compat import BaseModel, ValidationError, parse_obj_as
3226
from synapse.config._base import ConfigError
3327
from synapse.types import JsonDict, StrSequence
3428

synapse/config/workers.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,17 @@
2222

2323
import argparse
2424
import logging
25-
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union
25+
from typing import Any, Dict, List, Optional, Union
2626

2727
import attr
2828

29-
from synapse._pydantic_compat import HAS_PYDANTIC_V2
30-
31-
if TYPE_CHECKING or HAS_PYDANTIC_V2:
32-
from pydantic.v1 import BaseModel, Extra, StrictBool, StrictInt, StrictStr
33-
else:
34-
from pydantic import BaseModel, Extra, StrictBool, StrictInt, StrictStr
35-
29+
from synapse._pydantic_compat import (
30+
BaseModel,
31+
Extra,
32+
StrictBool,
33+
StrictInt,
34+
StrictStr,
35+
)
3636
from synapse.config._base import (
3737
Config,
3838
ConfigError,

synapse/events/validator.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,11 @@
1919
#
2020
#
2121
import collections.abc
22-
from typing import TYPE_CHECKING, List, Type, Union, cast
22+
from typing import List, Type, Union, cast
2323

2424
import jsonschema
2525

26-
from synapse._pydantic_compat import HAS_PYDANTIC_V2
27-
28-
if TYPE_CHECKING or HAS_PYDANTIC_V2:
29-
from pydantic.v1 import Field, StrictBool, StrictStr
30-
else:
31-
from pydantic import Field, StrictBool, StrictStr
32-
26+
from synapse._pydantic_compat import Field, StrictBool, StrictStr
3327
from synapse.api.constants import (
3428
MAX_ALIAS_LENGTH,
3529
EventContentFields,

synapse/http/servlet.py

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,19 +37,17 @@
3737
overload,
3838
)
3939

40-
from synapse._pydantic_compat import HAS_PYDANTIC_V2
41-
42-
if TYPE_CHECKING or HAS_PYDANTIC_V2:
43-
from pydantic.v1 import BaseModel, MissingError, PydanticValueError, ValidationError
44-
from pydantic.v1.error_wrappers import ErrorWrapper
45-
else:
46-
from pydantic import BaseModel, MissingError, PydanticValueError, ValidationError
47-
from pydantic.error_wrappers import ErrorWrapper
48-
4940
from typing_extensions import Literal
5041

5142
from twisted.web.server import Request
5243

44+
from synapse._pydantic_compat import (
45+
BaseModel,
46+
ErrorWrapper,
47+
MissingError,
48+
PydanticValueError,
49+
ValidationError,
50+
)
5351
from synapse.api.errors import Codes, SynapseError
5452
from synapse.http import redact_uri
5553
from synapse.http.server import HttpServer

synapse/rest/admin/users.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727

2828
import attr
2929

30-
from synapse._pydantic_compat import HAS_PYDANTIC_V2
30+
from synapse._pydantic_compat import StrictBool
3131
from synapse.api.constants import Direction, UserTypes
3232
from synapse.api.errors import Codes, NotFoundError, SynapseError
3333
from synapse.http.servlet import (
@@ -56,11 +56,6 @@
5656
if TYPE_CHECKING:
5757
from synapse.server import HomeServer
5858

59-
if TYPE_CHECKING or HAS_PYDANTIC_V2:
60-
from pydantic.v1 import StrictBool
61-
else:
62-
from pydantic import StrictBool
63-
6459

6560
logger = logging.getLogger(__name__)
6661

synapse/rest/client/account.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,12 @@
2424
from typing import TYPE_CHECKING, List, Optional, Tuple
2525
from urllib.parse import urlparse
2626

27-
from synapse._pydantic_compat import HAS_PYDANTIC_V2
28-
29-
if TYPE_CHECKING or HAS_PYDANTIC_V2:
30-
from pydantic.v1 import StrictBool, StrictStr, constr
31-
else:
32-
from pydantic import StrictBool, StrictStr, constr
33-
3427
import attr
3528
from typing_extensions import Literal
3629

3730
from twisted.web.server import Request
3831

32+
from synapse._pydantic_compat import StrictBool, StrictStr, constr
3933
from synapse.api.constants import LoginType
4034
from synapse.api.errors import (
4135
Codes,

synapse/rest/client/devices.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,7 @@
2424
from http import HTTPStatus
2525
from typing import TYPE_CHECKING, List, Optional, Tuple
2626

27-
from synapse._pydantic_compat import HAS_PYDANTIC_V2
28-
29-
if TYPE_CHECKING or HAS_PYDANTIC_V2:
30-
from pydantic.v1 import Extra, StrictStr
31-
else:
32-
from pydantic import Extra, StrictStr
33-
27+
from synapse._pydantic_compat import Extra, StrictStr
3428
from synapse.api import errors
3529
from synapse.api.errors import NotFoundError, SynapseError, UnrecognizedRequestError
3630
from synapse.handlers.device import DeviceHandler

0 commit comments

Comments
 (0)