## Change Summary

This means `pydantic/__init__.py` is now lazy about all imports using `__getattr__`.

Import performance changes:
### Before

```
code/pydantic 0 ➤ pdm run python -m timeit -n 1 -r 1 "import pydantic"
1 loop, best of 1: 29.7 msec per loop
```

```
code/pydantic 0 ➤ pdm run python -m timeit -n 1 -r 1 "from pydantic import BaseModel"
1 loop, best of 1: 30.4 msec per loop
```

### After

```
code/pydantic 0 ➤ pdm run python -m timeit -n 1 -r 1 "import pydantic"
1 loop, best of 1: 4.8 msec per loop
```

```
(env3112) code/pydantic 0 ➤ pdm run python -m timeit -n 1 -r 1 "from pydantic import BaseModel"           
1 loop, best of 1: 18.7 msec per loop
```

Tuna output:

<img width="1421" alt="image" src="https://github.com/pydantic/pydantic/assets/4039449/0a57434e-fdda-4709-8793-d96c0a0ee762">

## Related issue number

As promised in https://github.com/pydantic/pydantic/pull/7423#issuecomment-1733361629.

## Checklist

* [x] The pull request title is a good summary of the changes - it will be used in the changelog
* [ ] Unit tests for the changes exist
* [x] Tests pass on CI
* [ ] Documentation reflects the changes where applicable
* [x] My PR is ready to review, **please add a comment including the phrase "please review" to assign reviewers**


Selected Reviewer: @sydney-runkle
Use `__getattr__` for all package imports, improve import time. ## Change Summary

This means `pydantic/__init__.py` is now lazy about all imports using `__getattr__`.

Import performance changes:
### Before

```
code/pydantic 0 ➤ pdm run python -m timeit -n 1 -r 1 "import pydantic"
1 loop, best of 1: 29.7 msec per loop
```

```
code/pydantic 0 ➤ pdm run python -m timeit -n 1 -r 1 "from pydantic import BaseModel"
1 loop, best of 1: 30.4 msec per loop
```

### After

```
code/pydantic 0 ➤ pdm run python -m timeit -n 1 -r 1 "import pydantic"
1 loop, best of 1: 4.8 msec per loop
```

```
(env3112) code/pydantic 0 ➤ pdm run python -m timeit -n 1 -r 1 "from pydantic import BaseModel"           
1 loop, best of 1: 18.7 msec per loop
```

Tuna output:

<img width="1421" alt="image" src="https://github.com/pydantic/pydantic/assets/4039449/0a57434e-fdda-4709-8793-d96c0a0ee762">

## Related issue number

As promised in https://github.com/pydantic/pydantic/pull/7423#issuecomment-1733361629.

## Checklist

* [x] The pull request title is a good summary of the changes - it will be used in the changelog
* [ ] Unit tests for the changes exist
* [x] Tests pass on CI
* [ ] Documentation reflects the changes where applicable
* [x] My PR is ready to review, **please add a comment including the phrase "please review" to assign reviewers**


Selected Reviewer: @sydney-runkle
"""
Check that all `Usage docs` tags in docstrings link to the latest version of pydantic.
"""
import re
import sys
from pathlib import Path

ROOT_DIR = Path(__file__).parent.parent
PYDANTIC_DIR = ROOT_DIR / 'pydantic'
version_file = PYDANTIC_DIR / 'version.py'


version = re.search(rb"VERSION = '(.*)'", version_file.read_bytes()).group(1)
version_major_minor = b'.'.join(version.split(b'.')[:2])
expected_base = b'https://docs.pydantic.dev/' + version_major_minor + b'/'

paths = sys.argv[1:]
error_count = 0
for path_str in paths:
    path = ROOT_DIR / path_str
    b = path.read_bytes()

    changed = 0

    def sub(m: re.Match) -> bytes:
        global changed
        if m.group(2) != expected_base:
            changed += 1
            return m.group(1) + expected_base
        else:
            return m.group(0)

    b = re.sub(rb'(""" *usage.docs: *)(https://.+?/.+?/)', sub, b, flags=re.I)
    if changed:
        error_count += changed
        path.write_bytes(b)
        plural = 's' if changed > 1 else ''
        print(f'{path_str:50} {changed} usage docs link{plural} updated')

if error_count:
    sys.exit(1)

"""
Check that all `Usage docs` tags in docstrings link to the latest version of pydantic.
"""
import re
import sys
from pathlib import Path

ROOT_DIR = Path(__file__).parent.parent
PYDANTIC_DIR = ROOT_DIR / 'pydantic'
version_file = PYDANTIC_DIR / 'version.py'


version = re.search(rb"VERSION = '(.*)'", version_file.read_bytes()).group(1)
version_major_minor = b'.'.join(version.split(b'.')[:2])
expected_base = b'https://docs.pydantic.dev/' + version_major_minor + b'/'

paths = sys.argv[1:]
error_count = 0
for path_str in paths:
    path = ROOT_DIR / path_str
    b = path.read_bytes()

    changed = 0

    def sub(m: re.Match) -> bytes:
        global changed
        if m.group(2) != expected_base:
            changed += 1
            return m.group(1) + expected_base
        else:
            return m.group(0)

    b = re.sub(rb'(""" *usage.docs: *)(https://.+?/.+?/)', sub, b, flags=re.I)
    if changed:
        error_count += changed
        path.write_bytes(b)
        plural = 's' if changed > 1 else ''
        print(f'{path_str:50} {changed} usage docs link{plural} updated')

if error_count:
    sys.exit(1)
