Repository: litestar-org/litestar

Issue:
Bug: pydantic version logic breaks with latest pydantic
### Description

In [v1.10.15](https://github.com/pydantic/pydantic/releases/tag/v1.10.15) pydantic has added the `v1` namespace to the v1 line.

We rely on that not existing in the namespace to determine if we have v1 or v2 installed:

https://github.com/litestar-org/litestar/blob/13008fcfd54fcd15a33eb3a3d804506a3d2ce092/litestar/contrib/pydantic/pydantic_dto_factory.py#L26-L37


### URL to code causing the issue

_No response_

### MCVE

```python
peter@pop-os:~/litestar-test/litestar$ python -m venv .venv
peter@pop-os:~/litestar-test/litestar$ . .venv/bin/activate
(.venv) peter@pop-os:~/litestar-test/litestar$ python -m pip install litestar pydantic==1.*
Collecting litestar
  Using cached litestar-2.8.1-py3-none-any.whl.metadata (97 kB)
Collecting pydantic==1.*
  Downloading pydantic-1.10.15-py3-none-any.whl.metadata (150 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 150.6/150.6 kB 3.6 MB/s eta 0:00:00
... snipped ...
Installing collected packages: typing-extensions, sniffio, six, pyyaml, pygments, multidict, msgspec, mdurl, idna, h11, click, certifi, python-dateutil, pydantic, markdown-it-py, httpcore, anyio, rich, httpx, faker, rich-click, polyfactory, litestar
Successfully installed anyio-4.3.0 certifi-2024.2.2 click-8.1.7 faker-24.7.1 h11-0.14.0 httpcore-1.0.5 httpx-0.27.0 idna-3.6 litestar-2.8.1 markdown-it-py-3.0.0 mdurl-0.1.2 msgspec-0.18.6 multidict-6.0.5 polyfactory-2.15.0 pydantic-1.10.15 pygments-2.17.2 python-dateutil-2.9.0.post0 pyyaml-6.0.1 rich-13.7.1 rich-click-1.7.4 six-1.16.0 sniffio-1.3.1 typing-extensions-4.11.0
(.venv) peter@pop-os:~/litestar-test/litestar$ python -c "from litestar.contrib.pydantic import pydantic_dto_factory"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/home/peter/litestar-test/litestar/litestar/contrib/pydantic/__init__.py", line 8, in <module>
    from .pydantic_dto_factory import PydanticDTO
  File "/home/peter/litestar-test/litestar/litestar/contrib/pydantic/pydantic_dto_factory.py", line 59, in <module>
    pydantic_v2.JsonValue: Any,
    ^^^^^^^^^^^^^^^^^^^^^
AttributeError: module 'pydantic' has no attribute 'JsonValue'
(.venv) peter@pop-os:~/litestar-test/litestar$
```


### Steps to reproduce

```bash
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
```


### Screenshots

```bash
"![SCREENSHOT_DESCRIPTION](SCREENSHOT_LINK.png)"
```


### Logs

_No response_

### Litestar Version

v2.8.1

### Platform

- [X] Linux
- [ ] Mac
- [ ] Windows
- [ ] Other (Please specify in the description above)

<!-- POLAR PLEDGE BADGE START -->
---
> [!NOTE]  
> While we are open for sponsoring on [GitHub Sponsors](https://github.com/sponsors/litestar-org/) and 
> [OpenCollective](https://opencollective.com/litestar), we also utilize [Polar.sh](https://polar.sh/) to engage in pledge-based sponsorship.
>
> Check out all issues funded or available for funding [on our Polar.sh dashboard](https://polar.sh/litestar-org)
> * If you would like to see an issue prioritized, make a pledge towards it!
> * We receive the pledge once the issue is completed & verified
> * This, along with engagement in the community, helps us know which features are a priority to our users.

<a href="https://polar.sh/litestar-org/litestar/issues/3348">
<picture>
  <source media="(prefers-color-scheme: dark)" srcset="https://polar.sh/api/github/litestar-org/litestar/issues/3348/pledge.svg?darkmode=1">
  <img alt="Fund with Polar" src="https://polar.sh/api/github/litestar-org/litestar/issues/3348/pledge.svg">
</picture>
</a>
<!-- POLAR PLEDGE BADGE END -->



Discussion:

Resolving patch:
diff --git a/litestar/contrib/pydantic/pydantic_dto_factory.py b/litestar/contrib/pydantic/pydantic_dto_factory.py
--- a/litestar/contrib/pydantic/pydantic_dto_factory.py
+++ b/litestar/contrib/pydantic/pydantic_dto_factory.py
@@ -25,13 +25,16 @@
 
 try:
     import pydantic as pydantic_v2
+
+    assert pydantic_v2.__version__.startswith("2.")  # noqa: S101
+
     from pydantic import ValidationError as ValidationErrorV2
     from pydantic import v1 as pydantic_v1
     from pydantic.v1 import ValidationError as ValidationErrorV1
 
     ModelType: TypeAlias = "pydantic_v1.BaseModel | pydantic_v2.BaseModel"
 
-except ImportError:
+except AssertionError:
     import pydantic as pydantic_v1  # type: ignore[no-redef]
 
     pydantic_v2 = Empty  # type: ignore[assignment]
diff --git a/litestar/contrib/pydantic/pydantic_init_plugin.py b/litestar/contrib/pydantic/pydantic_init_plugin.py
--- a/litestar/contrib/pydantic/pydantic_init_plugin.py
+++ b/litestar/contrib/pydantic/pydantic_init_plugin.py
@@ -14,18 +14,23 @@
 from litestar.typing import _KWARG_META_EXTRACTORS
 from litestar.utils import is_class_and_subclass
 
+try:
+    import pydantic as _  # noqa: F401
+except ImportError as e:
+    raise MissingDependencyException("pydantic") from e
+
 try:
     # check if we have pydantic v2 installed, and try to import both versions
     import pydantic as pydantic_v2
+
+    assert pydantic_v2.__version__.startswith("2.")  # noqa: S101
+
     from pydantic import v1 as pydantic_v1
-except ImportError:
+except AssertionError:
     # check if pydantic 1 is installed and import it
-    try:
-        import pydantic as pydantic_v1  # type: ignore[no-redef]
+    import pydantic as pydantic_v1  # type: ignore[no-redef]
 
-        pydantic_v2 = None  # type: ignore[assignment]
-    except ImportError as e:
-        raise MissingDependencyException("pydantic") from e
+    pydantic_v2 = None  # type: ignore[assignment]
 
 
 if TYPE_CHECKING:
diff --git a/litestar/contrib/pydantic/pydantic_schema_plugin.py b/litestar/contrib/pydantic/pydantic_schema_plugin.py
--- a/litestar/contrib/pydantic/pydantic_schema_plugin.py
+++ b/litestar/contrib/pydantic/pydantic_schema_plugin.py
@@ -20,18 +20,23 @@
 from litestar.typing import FieldDefinition
 from litestar.utils import is_class_and_subclass, is_generic
 
+try:
+    import pydantic as _  # noqa: F401
+except ImportError as e:
+    raise MissingDependencyException("pydantic") from e
+
 try:
     # check if we have pydantic v2 installed, and try to import both versions
     import pydantic as pydantic_v2
+
+    assert pydantic_v2.__version__.startswith("2.")  # noqa: S101
+
     from pydantic import v1 as pydantic_v1
-except ImportError:
+except AssertionError:
     # check if pydantic 1 is installed and import it
-    try:
-        import pydantic as pydantic_v1  # type: ignore[no-redef]
+    import pydantic as pydantic_v1  # type: ignore[no-redef]
 
-        pydantic_v2 = None  # type: ignore[assignment]
-    except ImportError as e:
-        raise MissingDependencyException("pydantic") from e
+    pydantic_v2 = None  # type: ignore[assignment]
 
 if TYPE_CHECKING:
     from litestar._openapi.schema_generation.schema import SchemaCreator


Test patch:
diff --git a/test_apps/pydantic_1_app.py b/test_apps/pydantic_1_app.py
--- a/test_apps/pydantic_1_app.py
+++ b/test_apps/pydantic_1_app.py
@@ -19,6 +19,8 @@ async def handler(data: Foo) -> Foo:
 
 class TestApp(unittest.TestCase):
     def test_app(self) -> None:
+        assert pydantic.__version__.startswith("1."), pydantic.__version__
+
         with create_test_client([handler]) as client:
             data = {"bar": "baz", "baz": ["a", "b", "c"]}
             res = client.post("/", json=data)