Files
django-stubs/django_stubs_ext/tests/test_monkeypatching.py
Nikita Sobolev 0bb1182c42 Fix CI (#1108)
* Fix CI

* Fix CI

* Fix CI

* Fix CI

* APply black

* APply black

* Fix mypy

* Fix mypy errors in django-stubs

* Fix format

* Fix plugin

* Do not patch builtins by default

* Fix mypy

* Only run mypy on 3.10 for now

* Only run mypy on 3.10 for now

* WHAT THE HELL

* Enable strict mode in mypy

* Enable strict mode in mypy

* Fix tests

* Fix tests

* Debug

* Debug

* Fix tests

* Fix tests

* Add TYPE_CHECKING debug

* Caching maybe?

* Caching maybe?

* Try explicit `${{ matrix.python-version }}`

* Remove debug

* Fix typing

* Finally
2022-08-26 13:22:55 +03:00

137 lines
3.9 KiB
Python

import builtins
from contextlib import suppress
from typing import Iterable, List, Optional
import pytest
from _pytest.fixtures import FixtureRequest
from _pytest.monkeypatch import MonkeyPatch
from django.db.models import Model
from django.forms.models import ModelForm
from typing_extensions import Protocol
import django_stubs_ext
from django_stubs_ext import patch
from django_stubs_ext.patch import _need_generic, _VersionSpec
class _MakeGenericClasses(Protocol):
"""Used to represent a type of ``make_generic_classes`` fixture."""
def __call__(
self,
django_version: Optional[_VersionSpec] = None,
extra_classes: Optional[Iterable[type]] = None,
include_builtins: bool = True,
) -> None:
...
@pytest.fixture(scope="function")
def make_generic_classes(
request: FixtureRequest,
monkeypatch: MonkeyPatch,
) -> _MakeGenericClasses:
_extra_classes: List[type] = []
def fin() -> None:
for el in _need_generic:
with suppress(AttributeError):
delattr(el.cls, "__class_getitem__")
for cls in _extra_classes:
with suppress(AttributeError):
delattr(cls, "__class_getitem__")
_extra_classes.clear()
with suppress(AttributeError):
del builtins.reveal_type
with suppress(AttributeError):
del builtins.reveal_locals
def factory(
django_version: Optional[_VersionSpec] = None,
extra_classes: Optional[Iterable[type]] = None,
include_builtins: bool = True,
) -> None:
if extra_classes:
_extra_classes.extend(extra_classes)
if django_version is not None:
monkeypatch.setattr(patch, "VERSION", django_version)
django_stubs_ext.monkeypatch(extra_classes=extra_classes, include_builtins=include_builtins)
request.addfinalizer(fin)
return factory
def test_patched_generics(make_generic_classes: _MakeGenericClasses) -> None:
"""Test that the generics actually get patched."""
make_generic_classes()
for el in _need_generic:
if el.version is None:
assert el.cls[type] is el.cls # `type` is arbitrary
class TestForm(ModelForm[Model]):
pass
def test_patched_extra_classes_generics(make_generic_classes: _MakeGenericClasses) -> None:
"""Test that the generics actually get patched for extra classes."""
class _NotGeneric:
pass
extra_classes = [_NotGeneric]
make_generic_classes(django_version=None, extra_classes=extra_classes)
for cls in extra_classes:
assert cls[type] is cls # type: ignore[misc]
class _TestGeneric(_NotGeneric[Model]): # type: ignore
pass
@pytest.mark.parametrize(
"django_version",
[
(2, 2),
(3, 0),
(3, 1),
(3, 2),
(4, 0),
(4, 1),
],
)
def test_patched_version_specific(
django_version: _VersionSpec,
make_generic_classes: _MakeGenericClasses,
) -> None:
"""Test version speicific types."""
make_generic_classes(django_version)
for el in _need_generic:
if el.version is not None and django_version <= el.version:
assert el.cls[int] is el.cls
def test_mypy_builtins_not_patched_globally(
make_generic_classes: _MakeGenericClasses,
) -> None:
"""Ensures that builtins are not patched with `mypy` specific helpers.
This should only happend during `django.setup()`
(https://github.com/typeddjango/django-stubs/issues/609).
"""
make_generic_classes(include_builtins=False)
assert not hasattr(builtins, "reveal_type")
assert not hasattr(builtins, "reveal_locals")
def test_mypy_builtins_patched(
make_generic_classes: _MakeGenericClasses,
) -> None:
"""Ensures that builtins are patched by default."""
make_generic_classes()
assert hasattr(builtins, "reveal_type")
assert hasattr(builtins, "reveal_locals")