git: ab86f311f99e - main - devel/py-pydantic2: Allow build with py-pydantic-core 2.25.0
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sat, 26 Oct 2024 23:32:59 UTC
The branch main has been updated by sunpoet:
URL: https://cgit.FreeBSD.org/ports/commit/?id=ab86f311f99e6c9d92e0572a7f474bb857580d5f
commit ab86f311f99e6c9d92e0572a7f474bb857580d5f
Author: Po-Chuan Hsieh <sunpoet@FreeBSD.org>
AuthorDate: 2024-10-26 23:26:40 +0000
Commit: Po-Chuan Hsieh <sunpoet@FreeBSD.org>
CommitDate: 2024-10-26 23:26:40 +0000
devel/py-pydantic2: Allow build with py-pydantic-core 2.25.0
- Bump PORTREVISION for package change
Obtained from: https://github.com/pydantic/pydantic/commit/27afdfc9120c7a5b1071d907a25c37b46b103292
---
devel/py-pydantic2/Makefile | 4 +-
devel/py-pydantic2/files/patch-pydantic-core | 768 ++++++++++++++++++++++++++-
2 files changed, 769 insertions(+), 3 deletions(-)
diff --git a/devel/py-pydantic2/Makefile b/devel/py-pydantic2/Makefile
index 213ebb1c44ad..62e98e887b3f 100644
--- a/devel/py-pydantic2/Makefile
+++ b/devel/py-pydantic2/Makefile
@@ -1,6 +1,6 @@
PORTNAME= pydantic
PORTVERSION= 2.9.2
-PORTREVISION= 3
+PORTREVISION= 4
CATEGORIES= devel python
MASTER_SITES= PYPI
PKGNAMEPREFIX= ${PYTHON_PKGNAMEPREFIX}
@@ -17,7 +17,7 @@ LICENSE_FILE= ${WRKSRC}/LICENSE
BUILD_DEPENDS= ${PYTHON_PKGNAMEPREFIX}hatch-fancy-pypi-readme>=22.5.0:devel/py-hatch-fancy-pypi-readme@${PY_FLAVOR} \
${PYTHON_PKGNAMEPREFIX}hatchling>=0:devel/py-hatchling@${PY_FLAVOR}
RUN_DEPENDS= ${PYTHON_PKGNAMEPREFIX}annotated-types>=0.6.0:devel/py-annotated-types@${PY_FLAVOR} \
- ${PYTHON_PKGNAMEPREFIX}pydantic-core>=2.24.2<2.24.2_99:devel/py-pydantic-core@${PY_FLAVOR} \
+ ${PYTHON_PKGNAMEPREFIX}pydantic-core>=2.25.0<2.25.0_99:devel/py-pydantic-core@${PY_FLAVOR} \
${PYTHON_PKGNAMEPREFIX}typing-extensions>=4.12.2:devel/py-typing-extensions@${PY_FLAVOR}
USES= python
diff --git a/devel/py-pydantic2/files/patch-pydantic-core b/devel/py-pydantic2/files/patch-pydantic-core
index 6d55d0804033..5e393098a21a 100644
--- a/devel/py-pydantic2/files/patch-pydantic-core
+++ b/devel/py-pydantic2/files/patch-pydantic-core
@@ -1,5 +1,6 @@
Obtained from: https://github.com/pydantic/pydantic/commit/9b69920888054df4ef544ecbdc03e09b90646ac2
https://github.com/pydantic/pydantic/commit/51cf3cbfa767abfba1048cae41ea766d6add4f4a
+ https://github.com/pydantic/pydantic/commit/27afdfc9120c7a5b1071d907a25c37b46b103292
--- pydantic/_internal/_config.py.orig 2020-02-02 00:00:00 UTC
+++ pydantic/_internal/_config.py
@@ -124,6 +125,761 @@ Obtained from: https://github.com/pydantic/pydantic/commit/9b69920888054df4ef544
return {'type': 'number'}
return {'type': 'string', 'format': 'duration'}
+--- pydantic/networks.py.orig 2020-02-02 00:00:00 UTC
++++ pydantic/networks.py
+@@ -4,13 +4,16 @@ import re
+
+ import dataclasses as _dataclasses
+ import re
++from dataclasses import fields
+ from importlib.metadata import version
+ from ipaddress import IPv4Address, IPv4Interface, IPv4Network, IPv6Address, IPv6Interface, IPv6Network
+-from typing import TYPE_CHECKING, Any
++from typing import TYPE_CHECKING, Any, ClassVar
+
+ from pydantic_core import MultiHostUrl, PydanticCustomError, Url, core_schema
+ from typing_extensions import Annotated, Self, TypeAlias
+
++from pydantic.errors import PydanticUserError
++
+ from ._internal import _fields, _repr, _schema_generation_shared
+ from ._migration import getattr_migration
+ from .annotated_handlers import GetCoreSchemaHandler
+@@ -86,136 +89,294 @@ class UrlConstraints(_fields.PydanticMetadata):
+ )
+ )
+
++ @property
++ def defined_constraints(self) -> dict[str, Any]:
++ """Fetch a key / value mapping of constraints to values that are not None. Used for core schema updates."""
++ return {field.name: getattr(self, field.name) for field in fields(self)}
+
+-AnyUrl = Url
+-"""Base type for all URLs.
+
+-* Any scheme allowed
+-* Top-level domain (TLD) not required
+-* Host required
++# TODO: there's a lot of repeated code in these two base classes - should we consolidate, or does that up
++# the complexity enough that it's not worth saving a few lines?
+
+-Assuming an input URL of `http://samuel:pass@example.com:8000/the/path/?query=here#fragment=is;this=bit`,
+-the types export the following properties:
+
+-- `scheme`: the URL scheme (`http`), always set.
+-- `host`: the URL host (`example.com`), always set.
+-- `username`: optional username if included (`samuel`).
+-- `password`: optional password if included (`pass`).
+-- `port`: optional port (`8000`).
+-- `path`: optional path (`/the/path/`).
+-- `query`: optional URL query (for example, `GET` arguments or "search string", such as `query=here`).
+-- `fragment`: optional fragment (`fragment=is;this=bit`).
+-"""
+-AnyHttpUrl = Annotated[Url, UrlConstraints(allowed_schemes=['http', 'https'])]
+-"""A type that will accept any http or https URL.
++class _BaseUrl(Url):
++ _constraints: ClassVar[UrlConstraints] = UrlConstraints()
+
+-* TLD not required
+-* Host required
+-"""
+-HttpUrl = Annotated[Url, UrlConstraints(max_length=2083, allowed_schemes=['http', 'https'])]
+-"""A type that will accept any http or https URL.
++ @classmethod
++ def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema:
++ if issubclass(cls, source):
++ return core_schema.url_schema(**cls._constraints.defined_constraints)
++ else:
++ schema = handler(source)
++ # TODO: this logic is used in types.py as well in the _check_annotated_type function, should we move that to somewhere more central?
++ if annotated_type := schema['type'] not in ('url', 'multi-host-url'):
++ raise PydanticUserError(
++ f"'{cls.__name__}' cannot annotate '{annotated_type}'.", code='invalid-annotated-type'
++ )
++ for constraint_key, constraint_value in cls._constraints.defined_constraints.items():
++ schema[constraint_key] = constraint_value
++ return schema
+
+-* TLD not required
+-* Host required
+-* Max length 2083
+
+-```py
+-from pydantic import BaseModel, HttpUrl, ValidationError
++class _BaseMultiHostUrl(MultiHostUrl):
++ _constraints: ClassVar[UrlConstraints] = UrlConstraints()
+
+-class MyModel(BaseModel):
+- url: HttpUrl
++ @classmethod
++ def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema:
++ if issubclass(cls, source):
++ return core_schema.multi_host_url_schema(**cls._constraints.defined_constraints)
++ else:
++ schema = handler(source)
++ # TODO: this logic is used in types.py as well in the _check_annotated_type function, should we move that to somewhere more central?
++ if annotated_type := schema['type'] not in ('url', 'multi-host-url'):
++ raise PydanticUserError(
++ f"'{cls.__name__}' cannot annotate '{annotated_type}'.", code='invalid-annotated-type'
++ )
++ for constraint_key, constraint_value in cls._constraints.defined_constraints.items():
++ schema[constraint_key] = constraint_value
++ return schema
+
+-m = MyModel(url='http://www.example.com') # (1)!
+-print(m.url)
+-#> http://www.example.com/
+
+-try:
+- MyModel(url='ftp://invalid.url')
+-except ValidationError as e:
+- print(e)
+- '''
+- 1 validation error for MyModel
+- url
+- URL scheme should be 'http' or 'https' [type=url_scheme, input_value='ftp://invalid.url', input_type=str]
+- '''
++class AnyUrl(_BaseUrl):
++ """Base type for all URLs.
+
+-try:
+- MyModel(url='not a url')
+-except ValidationError as e:
+- print(e)
+- '''
+- 1 validation error for MyModel
+- url
+- Input should be a valid URL, relative URL without a base [type=url_parsing, input_value='not a url', input_type=str]
+- '''
+-```
++ * Any scheme allowed
++ * Top-level domain (TLD) not required
++ * Host required
+
+-1. Note: mypy would prefer `m = MyModel(url=HttpUrl('http://www.example.com'))`, but Pydantic will convert the string to an HttpUrl instance anyway.
++ Assuming an input URL of `http://samuel:pass@example.com:8000/the/path/?query=here#fragment=is;this=bit`,
++ the types export the following properties:
+
+-"International domains" (e.g. a URL where the host or TLD includes non-ascii characters) will be encoded via
+-[punycode](https://en.wikipedia.org/wiki/Punycode) (see
+-[this article](https://www.xudongz.com/blog/2017/idn-phishing/) for a good description of why this is important):
++ - `scheme`: the URL scheme (`http`), always set.
++ - `host`: the URL host (`example.com`), always set.
++ - `username`: optional username if included (`samuel`).
++ - `password`: optional password if included (`pass`).
++ - `port`: optional port (`8000`).
++ - `path`: optional path (`/the/path/`).
++ - `query`: optional URL query (for example, `GET` arguments or "search string", such as `query=here`).
++ - `fragment`: optional fragment (`fragment=is;this=bit`).
++ """
+
+-```py
+-from pydantic import BaseModel, HttpUrl
++ _constraints = UrlConstraints(host_required=True)
+
+-class MyModel(BaseModel):
+- url: HttpUrl
++ @property
++ def host(self) -> str:
++ """The required URL host."""
++ ...
+
+-m1 = MyModel(url='http://puny£code.com')
+-print(m1.url)
+-#> http://xn--punycode-eja.com/
+-m2 = MyModel(url='https://www.аррӏе.com/')
+-print(m2.url)
+-#> https://www.xn--80ak6aa92e.com/
+-m3 = MyModel(url='https://www.example.珠宝/')
+-print(m3.url)
+-#> https://www.example.xn--pbt977c/
+-```
+
++class AnyHttpUrl(_BaseUrl):
++ """A type that will accept any http or https URL.
+
+-!!! warning "Underscores in Hostnames"
+- In Pydantic, underscores are allowed in all parts of a domain except the TLD.
+- Technically this might be wrong - in theory the hostname cannot have underscores, but subdomains can.
++ * TLD not required
++ * Host required
++ """
+
+- To explain this; consider the following two cases:
++ _constraints = UrlConstraints(host_required=True, allowed_schemes=['http', 'https'])
+
+- - `exam_ple.co.uk`: the hostname is `exam_ple`, which should not be allowed since it contains an underscore.
+- - `foo_bar.example.com` the hostname is `example`, which should be allowed since the underscore is in the subdomain.
++ @property
++ def host(self) -> str:
++ """The required URL host."""
++ ...
+
+- Without having an exhaustive list of TLDs, it would be impossible to differentiate between these two. Therefore
+- underscores are allowed, but you can always do further validation in a validator if desired.
+
+- Also, Chrome, Firefox, and Safari all currently accept `http://exam_ple.com` as a URL, so we're in good
+- (or at least big) company.
+-"""
+-AnyWebsocketUrl = Annotated[Url, UrlConstraints(allowed_schemes=['ws', 'wss'])]
+-"""A type that will accept any ws or wss URL.
++class HttpUrl(_BaseUrl):
++ """A type that will accept any http or https URL.
+
+-* TLD not required
+-* Host required
+-"""
+-WebsocketUrl = Annotated[Url, UrlConstraints(max_length=2083, allowed_schemes=['ws', 'wss'])]
+-"""A type that will accept any ws or wss URL.
++ * TLD not required
++ * Host required
++ * Max length 2083
+
+-* TLD not required
+-* Host required
+-* Max length 2083
+-"""
+-FileUrl = Annotated[Url, UrlConstraints(allowed_schemes=['file'])]
+-"""A type that will accept any file URL.
++ ```py
++ from pydantic import BaseModel, HttpUrl, ValidationError
+
+-* Host not required
+-"""
+-FtpUrl = Annotated[Url, UrlConstraints(allowed_schemes=['ftp'])]
+-"""A type that will accept ftp URL.
++ class MyModel(BaseModel):
++ url: HttpUrl
+
+-* TLD not required
+-* Host required
+-"""
+-PostgresDsn = Annotated[
+- MultiHostUrl,
+- UrlConstraints(
++ m = MyModel(url='http://www.example.com') # (1)!
++ print(m.url)
++ #> http://www.example.com/
++
++ try:
++ MyModel(url='ftp://invalid.url')
++ except ValidationError as e:
++ print(e)
++ '''
++ 1 validation error for MyModel
++ url
++ URL scheme should be 'http' or 'https' [type=url_scheme, input_value='ftp://invalid.url', input_type=str]
++ '''
++
++ try:
++ MyModel(url='not a url')
++ except ValidationError as e:
++ print(e)
++ '''
++ 1 validation error for MyModel
++ url
++ Input should be a valid URL, relative URL without a base [type=url_parsing, input_value='not a url', input_type=str]
++ '''
++ ```
++
++ 1. Note: mypy would prefer `m = MyModel(url=HttpUrl('http://www.example.com'))`, but Pydantic will convert the string to an HttpUrl instance anyway.
++
++ "International domains" (e.g. a URL where the host or TLD includes non-ascii characters) will be encoded via
++ [punycode](https://en.wikipedia.org/wiki/Punycode) (see
++ [this article](https://www.xudongz.com/blog/2017/idn-phishing/) for a good description of why this is important):
++
++ ```py
++ from pydantic import BaseModel, HttpUrl
++
++ class MyModel(BaseModel):
++ url: HttpUrl
++
++ m1 = MyModel(url='http://puny£code.com')
++ print(m1.url)
++ #> http://xn--punycode-eja.com/
++ m2 = MyModel(url='https://www.аррӏе.com/')
++ print(m2.url)
++ #> https://www.xn--80ak6aa92e.com/
++ m3 = MyModel(url='https://www.example.珠宝/')
++ print(m3.url)
++ #> https://www.example.xn--pbt977c/
++ ```
++
++
++ !!! warning "Underscores in Hostnames"
++ In Pydantic, underscores are allowed in all parts of a domain except the TLD.
++ Technically this might be wrong - in theory the hostname cannot have underscores, but subdomains can.
++
++ To explain this; consider the following two cases:
++
++ - `exam_ple.co.uk`: the hostname is `exam_ple`, which should not be allowed since it contains an underscore.
++ - `foo_bar.example.com` the hostname is `example`, which should be allowed since the underscore is in the subdomain.
++
++ Without having an exhaustive list of TLDs, it would be impossible to differentiate between these two. Therefore
++ underscores are allowed, but you can always do further validation in a validator if desired.
++
++ Also, Chrome, Firefox, and Safari all currently accept `http://exam_ple.com` as a URL, so we're in good
++ (or at least big) company.
++ """
++
++ _constraints = UrlConstraints(max_length=2083, allowed_schemes=['http', 'https'], host_required=True)
++
++ @property
++ def host(self) -> str:
++ """The required URL host."""
++ ...
++
++
++class AnyWebsocketUrl(_BaseUrl):
++ """A type that will accept any ws or wss URL.
++
++ * TLD not required
++ * Host required
++ """
++
++ _constraints = UrlConstraints(allowed_schemes=['ws', 'wss'], host_required=True)
++
++ @property
++ def host(self) -> str:
++ """The required URL host."""
++ ...
++
++
++class WebsocketUrl(_BaseUrl):
++ """A type that will accept any ws or wss URL.
++
++ * TLD not required
++ * Host required
++ * Max length 2083
++ """
++
++ _constraints = UrlConstraints(max_length=2083, allowed_schemes=['ws', 'wss'], host_required=True)
++
++ @property
++ def host(self) -> str:
++ """The required URL host."""
++ ...
++
++
++class FileUrl(_BaseUrl):
++ """A type that will accept any file URL.
++
++ * Host not required
++ """
++
++ _constraints = UrlConstraints(allowed_schemes=['file'])
++
++
++class FtpUrl(_BaseUrl):
++ """A type that will accept ftp URL.
++
++ * TLD not required
++ * Host required
++ """
++
++ _constraints = UrlConstraints(allowed_schemes=['ftp'], host_required=True)
++
++
++class PostgresDsn(_BaseMultiHostUrl):
++ """A type that will accept any Postgres DSN.
++
++ * User info required
++ * TLD not required
++ * Host required
++ * Supports multiple hosts
++
++ If further validation is required, these properties can be used by validators to enforce specific behaviour:
++
++ ```py
++ from pydantic import (
++ BaseModel,
++ HttpUrl,
++ PostgresDsn,
++ ValidationError,
++ field_validator,
++ )
++
++ class MyModel(BaseModel):
++ url: HttpUrl
++
++ m = MyModel(url='http://www.example.com')
++
++ # the repr() method for a url will display all properties of the url
++ print(repr(m.url))
++ #> Url('http://www.example.com/')
++ print(m.url.scheme)
++ #> http
++ print(m.url.host)
++ #> www.example.com
++ print(m.url.port)
++ #> 80
++
++ class MyDatabaseModel(BaseModel):
++ db: PostgresDsn
++
++ @field_validator('db')
++ def check_db_name(cls, v):
++ assert v.path and len(v.path) > 1, 'database must be provided'
++ return v
++
++ m = MyDatabaseModel(db='postgres://user:pass@localhost:5432/foobar')
++ print(m.db)
++ #> postgres://user:pass@localhost:5432/foobar
++
++ try:
++ MyDatabaseModel(db='postgres://user:pass@localhost:5432')
++ except ValidationError as e:
++ print(e)
++ '''
++ 1 validation error for MyDatabaseModel
++ db
++ Assertion failed, database must be provided
++ assert (None)
++ + where None = MultiHostUrl('postgres://user:pass@localhost:5432').path [type=assertion_error, input_value='postgres://user:pass@localhost:5432', input_type=str]
++ '''
++ ```
++ """
++
++ _constraints = UrlConstraints(
+ host_required=True,
+ allowed_schemes=[
+ 'postgres',
+@@ -228,130 +389,118 @@ PostgresDsn = Annotated[
+ 'postgresql+py-postgresql',
+ 'postgresql+pygresql',
+ ],
+- ),
+-]
+-"""A type that will accept any Postgres DSN.
++ )
+
+-* User info required
+-* TLD not required
+-* Host required
+-* Supports multiple hosts
++ @property
++ def host(self) -> str:
++ """The required URL host."""
++ ...
+
+-If further validation is required, these properties can be used by validators to enforce specific behaviour:
+
+-```py
+-from pydantic import (
+- BaseModel,
+- HttpUrl,
+- PostgresDsn,
+- ValidationError,
+- field_validator,
+-)
++class CockroachDsn(_BaseUrl):
++ """A type that will accept any Cockroach DSN.
+
+-class MyModel(BaseModel):
+- url: HttpUrl
++ * User info required
++ * TLD not required
++ * Host required
++ """
+
+-m = MyModel(url='http://www.example.com')
++ _constraints = UrlConstraints(
++ host_required=True,
++ allowed_schemes=[
++ 'cockroachdb',
++ 'cockroachdb+psycopg2',
++ 'cockroachdb+asyncpg',
++ ],
++ )
+
+-# the repr() method for a url will display all properties of the url
+-print(repr(m.url))
+-#> Url('http://www.example.com/')
+-print(m.url.scheme)
+-#> http
+-print(m.url.host)
+-#> www.example.com
+-print(m.url.port)
+-#> 80
++ @property
++ def host(self) -> str:
++ """The required URL host."""
++ ...
+
+-class MyDatabaseModel(BaseModel):
+- db: PostgresDsn
+
+- @field_validator('db')
+- def check_db_name(cls, v):
+- assert v.path and len(v.path) > 1, 'database must be provided'
+- return v
++class AmqpDsn(_BaseUrl):
++ """A type that will accept any AMQP DSN.
+
+-m = MyDatabaseModel(db='postgres://user:pass@localhost:5432/foobar')
+-print(m.db)
+-#> postgres://user:pass@localhost:5432/foobar
++ * User info required
++ * TLD not required
++ * Host not required
++ """
+
+-try:
+- MyDatabaseModel(db='postgres://user:pass@localhost:5432')
+-except ValidationError as e:
+- print(e)
+- '''
+- 1 validation error for MyDatabaseModel
+- db
+- Assertion failed, database must be provided
+- assert (None)
+- + where None = MultiHostUrl('postgres://user:pass@localhost:5432').path [type=assertion_error, input_value='postgres://user:pass@localhost:5432', input_type=str]
+- '''
+-```
+-"""
++ _constraints = UrlConstraints(allowed_schemes=['amqp', 'amqps'])
+
+-CockroachDsn = Annotated[
+- Url,
+- UrlConstraints(
++
++class RedisDsn(_BaseUrl):
++ """A type that will accept any Redis DSN.
++
++ * User info required
++ * TLD not required
++ * Host required (e.g., `rediss://:pass@localhost`)
++ """
++
++ _constraints = UrlConstraints(
++ allowed_schemes=['redis', 'rediss'],
++ default_host='localhost',
++ default_port=6379,
++ default_path='/0',
+ host_required=True,
+- allowed_schemes=[
+- 'cockroachdb',
+- 'cockroachdb+psycopg2',
+- 'cockroachdb+asyncpg',
+- ],
+- ),
+-]
+-"""A type that will accept any Cockroach DSN.
++ )
+
+-* User info required
+-* TLD not required
+-* Host required
+-"""
+-AmqpDsn = Annotated[Url, UrlConstraints(allowed_schemes=['amqp', 'amqps'])]
+-"""A type that will accept any AMQP DSN.
++ @property
++ def host(self) -> str:
++ """The required URL host."""
++ ...
+
+-* User info required
+-* TLD not required
+-* Host required
+-"""
+-RedisDsn = Annotated[
+- Url,
+- UrlConstraints(allowed_schemes=['redis', 'rediss'], default_host='localhost', default_port=6379, default_path='/0'),
+-]
+-"""A type that will accept any Redis DSN.
+
+-* User info required
+-* TLD not required
+-* Host required (e.g., `rediss://:pass@localhost`)
+-"""
+-MongoDsn = Annotated[MultiHostUrl, UrlConstraints(allowed_schemes=['mongodb', 'mongodb+srv'], default_port=27017)]
+-"""A type that will accept any MongoDB DSN.
++class MongoDsn(_BaseMultiHostUrl):
++ """A type that will accept any MongoDB DSN.
+
+-* User info not required
+-* Database name not required
+-* Port not required
+-* User info may be passed without user part (e.g., `mongodb://mongodb0.example.com:27017`).
+-"""
+-KafkaDsn = Annotated[Url, UrlConstraints(allowed_schemes=['kafka'], default_host='localhost', default_port=9092)]
+-"""A type that will accept any Kafka DSN.
++ * User info not required
++ * Database name not required
++ * Port not required
++ * User info may be passed without user part (e.g., `mongodb://mongodb0.example.com:27017`).
++ """
+
+-* User info required
+-* TLD not required
+-* Host required
+-"""
+-NatsDsn = Annotated[
+- MultiHostUrl,
+- UrlConstraints(allowed_schemes=['nats', 'tls', 'ws', 'wss'], default_host='localhost', default_port=4222),
+-]
+-"""A type that will accept any NATS DSN.
++ _constraints = UrlConstraints(allowed_schemes=['mongodb', 'mongodb+srv'], default_port=27017)
+
+-NATS is a connective technology built for the ever increasingly hyper-connected world.
+-It is a single technology that enables applications to securely communicate across
+-any combination of cloud vendors, on-premise, edge, web and mobile, and devices.
+-More: https://nats.io
+-"""
+-MySQLDsn = Annotated[
+- Url,
+- UrlConstraints(
++
++class KafkaDsn(_BaseUrl):
++ """A type that will accept any Kafka DSN.
++
++ * User info required
++ * TLD not required
++ * Host required
++ """
++
++ _constraints = UrlConstraints(
++ allowed_schemes=['kafka'], default_host='localhost', default_port=9092, host_required=True
++ )
++
++
++class NatsDsn(_BaseMultiHostUrl):
++ """A type that will accept any NATS DSN.
++
++ NATS is a connective technology built for the ever increasingly hyper-connected world.
++ It is a single technology that enables applications to securely communicate across
++ any combination of cloud vendors, on-premise, edge, web and mobile, and devices.
++ More: https://nats.io
++ """
++
++ _constraints = UrlConstraints(
++ allowed_schemes=['nats', 'tls', 'ws', 'wss'], default_host='localhost', default_port=4222
++ )
++
++
++class MySQLDsn(_BaseUrl):
++ """A type that will accept any MySQL DSN.
++
++ * User info required
++ * TLD not required
++ * Host required
++ """
++
++ _constraints = UrlConstraints(
+ allowed_schemes=[
+ 'mysql',
+ 'mysql+mysqlconnector',
+@@ -363,54 +512,73 @@ MySQLDsn = Annotated[
+ 'mysql+pyodbc',
+ ],
+ default_port=3306,
+- ),
+-]
+-"""A type that will accept any MySQL DSN.
++ host_required=True,
++ )
+
+-* User info required
+-* TLD not required
+-* Host required
+-"""
+-MariaDBDsn = Annotated[
+- Url,
+- UrlConstraints(
++ @property
++ def host(self) -> str:
++ """The required URL host."""
++ ...
++
++
++class MariaDBDsn(_BaseUrl):
++ """A type that will accept any MariaDB DSN.
++
++ * User info required
++ * TLD not required
++ * Host required
++ """
++
++ _constraints = UrlConstraints(
+ allowed_schemes=['mariadb', 'mariadb+mariadbconnector', 'mariadb+pymysql'],
+ default_port=3306,
+- ),
+-]
+-"""A type that will accept any MariaDB DSN.
++ host_required=True,
++ )
+
+-* User info required
+-* TLD not required
+-* Host required
+-"""
+-ClickHouseDsn = Annotated[
+- Url,
+- UrlConstraints(
++ @property
++ def host(self) -> str:
++ """The required URL host."""
++ ...
++
++
++class ClickHouseDsn(_BaseUrl):
++ """A type that will accept any ClickHouse DSN.
++
++ * User info required
++ * TLD not required
++ * Host required
++ """
++
++ _constraints = UrlConstraints(
+ allowed_schemes=['clickhouse+native', 'clickhouse+asynch'],
+ default_host='localhost',
+ default_port=9000,
+- ),
+-]
+-"""A type that will accept any ClickHouse DSN.
++ host_required=True,
++ )
+
+-* User info required
+-* TLD not required
+-* Host required
+-"""
+-SnowflakeDsn = Annotated[
+- Url,
+- UrlConstraints(
++ @property
++ def host(self) -> str:
++ """The required URL host."""
++ ...
++
++
++class SnowflakeDsn(_BaseUrl):
++ """A type that will accept any Snowflake DSN.
++
++ * User info required
++ * TLD not required
++ * Host required
++ """
++
++ _constraints = UrlConstraints(
+ allowed_schemes=['snowflake'],
+ host_required=True,
+- ),
+-]
+-"""A type that will accept any Snowflake DSN.
++ )
+
+-* User info required
+-* TLD not required
+-* Host required
+-"""
++ @property
++ def host(self) -> str:
++ """The required URL host."""
++ ...
+
+
+ def import_email_validator() -> None:
--- pydantic/warnings.py.orig 2020-02-02 00:00:00 UTC
+++ pydantic/warnings.py
@@ -67,6 +67,13 @@ class PydanticDeprecatedSince29(PydanticDeprecationWar
@@ -147,7 +903,7 @@ Obtained from: https://github.com/pydantic/pydantic/commit/9b69920888054df4ef544
'typing-extensions>=4.12.2; python_version >= "3.13"',
'annotated-types>=0.6.0',
- "pydantic-core==2.23.4",
-+ "pydantic-core==2.24.2",
++ "pydantic-core==2.25.0",
]
dynamic = ['version', 'readme']
@@ -298,3 +1054,13 @@ Obtained from: https://github.com/pydantic/pydantic/commit/9b69920888054df4ef544
@pytest.mark.parametrize(
+--- tests/test_networks.py.orig 2020-02-02 00:00:00 UTC
++++ tests/test_networks.py
+@@ -107,7 +107,6 @@ except ImportError:
+ 'http://example.org/path#fragment',
+ 'http://example.org/path?query#',
+ 'http://example.org/path?query#fragment',
+- 'file://localhost/foo/bar',
+ ],
+ )
+ def test_any_url_success(value):