Repository: pydantic/pydantic

Issue:
MongoDsn.build gives AttributeError
### Initial Checks

- [X] I confirm that I'm using Pydantic V2

### Description

Using build on MongoDsn gives error:

    url = MongoDsn.build(scheme=scheme, username=username, password=password, host=host)
          ^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/typing.py", line 1287, in __getattr__
    return getattr(self.__origin__, attr)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/typing.py", line 450, in __getattr__
    raise AttributeError(item)
AttributeError: build


### Example Code

```Python
url = MongoDsn.build(scheme=scheme, username=username, password=password, host=host)
```


### Python, Pydantic & OS Version

```Text
pydantic version: 2.1.1
        pydantic-core version: 2.4.0
          pydantic-core build: profile=release pgo=true mimalloc=true
               python version: 3.11.4 (main, Jun  7 2023, 12:45:48) [GCC 11.3.0]
                     platform: Linux-5.19.0-50-generic-x86_64-with-glibc2.35
     optional deps. installed: ['typing-extensions']
```


Selected Assignee: @hramezani


Discussion:
Additionally, if build url using MultiHostUrl and then create instance of MongoDsn from it:

url = MultiHostUrl.build(scheme=scheme, username=username, password=password, host=host)
MongoDsn(url)

Will give the error:

MongoDsn(url)
           ^^^^^^^^^^^^^
  File "/usr/lib/python3.11/typing.py", line 1261, in __call__
    result = self.__origin__(*args, **kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/typing.py", line 462, in __call__
    raise TypeError(f"Cannot instantiate {self!r}")
TypeError: Cannot instantiate typing.Union

~It doesn't look like you are in the latest version of Pydantic 🤔~

~You sure you are using the version 2.1.1?~

Caused by https://github.com/pydantic/pydantic/pull/6827


Resolving patch:
diff --git a/pydantic/networks.py b/pydantic/networks.py
--- a/pydantic/networks.py
+++ b/pydantic/networks.py
@@ -4,7 +4,7 @@
 import dataclasses as _dataclasses
 import re
 from ipaddress import IPv4Address, IPv4Interface, IPv4Network, IPv6Address, IPv6Interface, IPv6Network
-from typing import TYPE_CHECKING, Any, Union
+from typing import TYPE_CHECKING, Any
 
 from pydantic_core import MultiHostUrl, PydanticCustomError, Url, core_schema
 from typing_extensions import Annotated, TypeAlias
@@ -124,10 +124,7 @@ def __hash__(self) -> int:
     UrlConstraints(allowed_schemes=['redis', 'rediss'], default_host='localhost', default_port=6379, default_path='/0'),
 ]
 """A type that will accept any Redis DSN."""
-MongoDsn = Union[
-    Annotated[MultiHostUrl, UrlConstraints(allowed_schemes=['mongodb'], default_port=27017)],
-    Annotated[MultiHostUrl, UrlConstraints(allowed_schemes=['mongodb+srv'])],
-]
+MongoDsn = Annotated[MultiHostUrl, UrlConstraints(allowed_schemes=['mongodb', 'mongodb+srv'], default_port=27017)]
 """A type that will accept any MongoDB DSN."""
 KafkaDsn = Annotated[Url, UrlConstraints(allowed_schemes=['kafka'], default_host='localhost', default_port=9092)]
 """A type that will accept any Kafka DSN."""


Test patch:
diff --git a/tests/test_networks.py b/tests/test_networks.py
--- a/tests/test_networks.py
+++ b/tests/test_networks.py
@@ -615,14 +615,28 @@ class Model(BaseModel):
     assert m.a.hosts() == [{'username': None, 'password': None, 'host': 'localhost', 'port': 27017}]
 
 
-def test_mongodsn_default_ports():
+@pytest.mark.parametrize(
+    ('dsn', 'expected'),
+    [
+        ('mongodb://user:pass@localhost/app', 'mongodb://user:pass@localhost:27017/app'),
+        pytest.param(
+            'mongodb+srv://user:pass@localhost/app',
+            'mongodb+srv://user:pass@localhost/app',
+            marks=pytest.mark.xfail(
+                reason=(
+                    'This case is not supported. '
+                    'Check https://github.com/pydantic/pydantic/pull/7116 for more details.'
+                )
+            ),
+        ),
+    ],
+)
+def test_mongodsn_default_ports(dsn: str, expected: str):
     class Model(BaseModel):
-        a: MongoDsn
+        dsn: MongoDsn
 
-    m1 = Model(a='mongodb://user:pass@localhost/app')
-    m2 = Model(a='mongodb+srv://user:pass@localhost/app')
-    assert str(m1.a) == 'mongodb://user:pass@localhost:27017/app'
-    assert str(m2.a) == 'mongodb+srv://user:pass@localhost/app'
+    m = Model(dsn=dsn)
+    assert str(m.dsn) == expected
 
 
 def test_kafka_dsns():