Skip to content

Commit

Permalink
Add pydantic 2 compatibility layer (#321)
Browse files Browse the repository at this point in the history
allow to use with pydantic 2

napari/napari#6350

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
Czaki and pre-commit-ci[bot] authored Oct 20, 2023
1 parent 8c58b91 commit 9d29e4d
Show file tree
Hide file tree
Showing 25 changed files with 105 additions and 42 deletions.
4 changes: 3 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,14 @@ jobs:
run: pipx run check-manifest

test:
name: ${{ matrix.platform }} (${{ matrix.python-version }})
name: ${{ matrix.platform }} (${{ matrix.python-version }}) ${{ matrix.pydantic }}
runs-on: ${{ matrix.platform }}
strategy:
fail-fast: false
matrix:
python-version: [3.8, 3.9, "3.10", "3.11"]
platform: [ubuntu-latest, macos-latest, windows-latest]
pydantic: ["pydantic<2", "pydantic>2"]

steps:
- uses: actions/checkout@v4
Expand All @@ -42,6 +43,7 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install "${{ matrix.pydantic }}"
pip install -e .[json,docs,testing]
- name: Test Main docs build
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ dependencies = [
"appdirs",
"build>=1",
"psygnal>=0.3.0",
"pydantic<2",
"pydantic",
"tomli-w",
"tomli; python_version < '3.11'",
"rich",
Expand Down
2 changes: 1 addition & 1 deletion src/npe2/_dynamic_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
overload,
)

from pydantic import BaseModel, ValidationError
from npe2._pydantic_compat import BaseModel, ValidationError

from ._plugin_manager import PluginManager
from .manifest.contributions import (
Expand Down
54 changes: 54 additions & 0 deletions src/npe2/_pydantic_compat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
try:
# pydantic v2
from pydantic.v1 import (
BaseModel,
Extra,
Field,
PrivateAttr,
ValidationError,
color,
conlist,
constr,
root_validator,
validator,
)
from pydantic.v1.error_wrappers import ErrorWrapper
from pydantic.v1.fields import SHAPE_LIST
from pydantic.v1.generics import GenericModel
from pydantic.v1.main import ModelMetaclass
except ImportError:
# pydantic v2
from pydantic import (
BaseModel,
Extra,
Field,
PrivateAttr,
ValidationError,
color,
conlist,
constr,
root_validator,
validator,
)
from pydantic.error_wrappers import ErrorWrapper
from pydantic.fields import SHAPE_LIST
from pydantic.generics import GenericModel
from pydantic.main import ModelMetaclass


__all__ = (
"BaseModel",
"Extra",
"Field",
"ValidationError",
"root_validator",
"validator",
"PrivateAttr",
"color",
"conlist",
"constr",
"ModelMetaclass",
"ErrorWrapper",
"GenericModel",
"SHAPE_LIST",
)
2 changes: 1 addition & 1 deletion src/npe2/implements.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from inspect import Parameter, Signature
from typing import Any, Callable, List, Sequence, Type, TypeVar

from pydantic import BaseModel
from npe2._pydantic_compat import BaseModel

from .manifest import contributions

Expand Down
2 changes: 1 addition & 1 deletion src/npe2/implements.pyi
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import Any, Callable, TypeVar

from pydantic import BaseModel as BaseModel
from npe2._pydantic_compat import BaseModel as BaseModel

from .manifest import PluginManifest as PluginManifest
from .manifest import contributions as contributions
Expand Down
3 changes: 2 additions & 1 deletion src/npe2/manifest/_bases.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
from typing import Callable, Dict, Optional, Union

import yaml
from pydantic import BaseModel, PrivateAttr

from npe2._pydantic_compat import BaseModel, PrivateAttr


class ImportExportModel(BaseModel):
Expand Down
10 changes: 8 additions & 2 deletions src/npe2/manifest/_package_metadata.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
from importlib import metadata
from typing import Dict, List, Literal, Optional, Union

from pydantic import BaseModel, Extra, Field, constr, root_validator
from pydantic.fields import SHAPE_LIST
from npe2._pydantic_compat import (
SHAPE_LIST,
BaseModel,
Extra,
Field,
constr,
root_validator,
)

# https://packaging.python.org/specifications/core-metadata/

Expand Down
3 changes: 1 addition & 2 deletions src/npe2/manifest/contributions/_commands.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from typing import TYPE_CHECKING, Any, Optional, Union

from pydantic import BaseModel, Extra, Field, validator

from npe2._pydantic_compat import BaseModel, Extra, Field, validator
from npe2.manifest import _validators
from npe2.types import PythonName

Expand Down
2 changes: 1 addition & 1 deletion src/npe2/manifest/contributions/_configuration.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import Any, Dict, List, Literal, Optional, Union

from pydantic import BaseModel, Field, conlist, root_validator, validator
from npe2._pydantic_compat import BaseModel, Field, conlist, root_validator, validator

from ._json_schema import (
Draft07JsonSchema,
Expand Down
2 changes: 1 addition & 1 deletion src/npe2/manifest/contributions/_contributions.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import Dict, List, Optional

from pydantic import BaseModel, Field, validator
from npe2._pydantic_compat import BaseModel, Field, validator

from ._commands import CommandContribution
from ._configuration import ConfigurationContribution
Expand Down
2 changes: 1 addition & 1 deletion src/npe2/manifest/contributions/_icon.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import Optional

from pydantic import BaseModel
from npe2._pydantic_compat import BaseModel


class Icon(BaseModel):
Expand Down
9 changes: 8 additions & 1 deletion src/npe2/manifest/contributions/_json_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,14 @@

from typing import TYPE_CHECKING, Any, Dict, List, Literal, Optional, Type, Union

from pydantic import BaseModel, Field, PrivateAttr, conlist, root_validator, validator
from npe2._pydantic_compat import (
BaseModel,
Field,
PrivateAttr,
conlist,
root_validator,
validator,
)

if TYPE_CHECKING:
from jsonschema.exceptions import ValidationError
Expand Down
3 changes: 1 addition & 2 deletions src/npe2/manifest/contributions/_keybindings.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from typing import Optional

from pydantic.fields import Field

from npe2._pydantic_compat import Field
from npe2.manifest.utils import Executable


Expand Down
3 changes: 1 addition & 2 deletions src/npe2/manifest/contributions/_menus.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from typing import Optional, Union

from pydantic import BaseModel, Field

from npe2._pydantic_compat import BaseModel, Field
from npe2.manifest.utils import Executable


Expand Down
3 changes: 1 addition & 2 deletions src/npe2/manifest/contributions/_readers.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
from functools import wraps
from typing import List, Optional

from pydantic import Extra, Field

from npe2._pydantic_compat import Extra, Field
from npe2.manifest.utils import Executable, v2_to_v1
from npe2.types import ReaderFunction

Expand Down
4 changes: 1 addition & 3 deletions src/npe2/manifest/contributions/_sample_data.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
from abc import ABC, abstractmethod
from typing import TYPE_CHECKING, List, Optional, Union

from pydantic.fields import Field
from pydantic.generics import GenericModel

from npe2._pydantic_compat import Field, GenericModel
from npe2.manifest.utils import Executable
from npe2.types import LayerData

Expand Down
3 changes: 1 addition & 2 deletions src/npe2/manifest/contributions/_submenu.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from typing import Optional, Union

from pydantic import BaseModel
from pydantic.fields import Field
from npe2._pydantic_compat import BaseModel, Field

from ._icon import Icon

Expand Down
3 changes: 1 addition & 2 deletions src/npe2/manifest/contributions/_themes.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import sys
from typing import Literal, Optional, Union

from pydantic import BaseModel, color
from pydantic.fields import Field
from npe2._pydantic_compat import BaseModel, Field, color


# pydantic doesn't implement color equality?
Expand Down
3 changes: 1 addition & 2 deletions src/npe2/manifest/contributions/_widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@

from typing import TYPE_CHECKING, Callable, Optional

from pydantic import Extra, Field

from npe2._pydantic_compat import Extra, Field
from npe2.manifest.utils import Executable
from npe2.types import Widget

Expand Down
3 changes: 1 addition & 2 deletions src/npe2/manifest/contributions/_writers.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
from enum import Enum
from typing import List, Tuple

from pydantic import BaseModel, Extra, Field, validator

from npe2._pydantic_compat import BaseModel, Extra, Field, validator
from npe2.manifest.utils import Executable


Expand Down
17 changes: 11 additions & 6 deletions src/npe2/manifest/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,16 @@
from pathlib import Path
from typing import Iterator, List, Literal, NamedTuple, Optional, Sequence, Union

from pydantic import Extra, Field, ValidationError, root_validator, validator
from pydantic.error_wrappers import ErrorWrapper
from pydantic.main import BaseModel, ModelMetaclass

from npe2._pydantic_compat import (
BaseModel,
ErrorWrapper,
Extra,
Field,
ModelMetaclass,
ValidationError,
root_validator,
validator,
)
from npe2.types import PythonName

from . import _validators
Expand Down Expand Up @@ -438,9 +444,8 @@ def _from_package_or_name(
If the name does not resolve to either a distribution name or a filename.
"""
from pydantic import ValidationError

from npe2 import PluginManifest
from npe2._pydantic_compat import ValidationError

try:
return PluginManifest.from_file(package_or_filename)
Expand Down
4 changes: 1 addition & 3 deletions src/npe2/manifest/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@
Union,
)

from pydantic import PrivateAttr
from pydantic.generics import GenericModel

from npe2._pydantic_compat import GenericModel, PrivateAttr
from npe2.types import PythonName

if TYPE_CHECKING:
Expand Down
2 changes: 1 addition & 1 deletion tests/test_manifest.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
from unittest.mock import patch

import pytest
from pydantic import ValidationError

from npe2 import PluginManifest
from npe2._pydantic_compat import ValidationError
from npe2.manifest import PackageMetadata
from npe2.manifest.schema import ENTRY_POINT

Expand Down
2 changes: 1 addition & 1 deletion tests/test_validations.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import json

import pytest
from pydantic import ValidationError

from npe2 import PluginManifest
from npe2._pydantic_compat import ValidationError
from npe2.manifest import _validators

# the docstrings here are used to assert the validation error that is printed.
Expand Down

0 comments on commit 9d29e4d

Please sign in to comment.