import copy import json import pickle from typing import ClassVar, Dict, List, Literal, TypeVar, Union # noqa: UP035 from pydantic import ValidationError import pytest from nonebot.compat import type_validate_python from nonebot.utils import ( UNSET, DataclassEncoder, Unset, UnsetType, escape_tag, exclude_unset, generic_check_issubclass, is_async_gen_callable, is_coroutine_callable, is_gen_callable, ) from utils import FakeMessage, FakeMessageSegment def test_unset(): assert isinstance(UNSET, Unset) assert bool(UNSET) is False assert copy.copy(UNSET) is UNSET assert copy.deepcopy(UNSET) is UNSET assert pickle.loads(pickle.dumps(UNSET)) is UNSET assert type_validate_python(UnsetType, UNSET) is UNSET with pytest.raises(ValidationError): type_validate_python(UnsetType, 123) def test_exclude_unset(): assert exclude_unset({"a": 1, "b": UNSET, "c": None, "d": {"x": UNSET}}) == { "a": 1, "c": None, "d": {}, } assert exclude_unset([1, UNSET, None, {"x": UNSET}]) == [1, None, {}] assert exclude_unset(UNSET) is None assert exclude_unset(123) == 123 def test_loguru_escape_tag(): assert escape_tag("red") == r"\red\" assert escape_tag("white") == r"\white\" assert escape_tag("white") == "\\white\\" assert escape_tag("white") == r"\white\" assert escape_tag("white") == "\\white\\" def test_generic_check_issubclass(): assert generic_check_issubclass(int, (int, float)) assert not generic_check_issubclass(str, (int, float)) assert generic_check_issubclass(Union[int, float, None], (int, float)) # noqa: UP007 assert generic_check_issubclass(int | float | None, (int, float)) assert generic_check_issubclass(Literal[1, 2, 3], int) assert not generic_check_issubclass(Literal[1, 2, "3"], int) assert generic_check_issubclass(List[int], list) # noqa: UP006 assert generic_check_issubclass(Dict[str, int], dict) # noqa: UP006 assert generic_check_issubclass(list[int], list) assert generic_check_issubclass(dict[str, int], dict) assert not generic_check_issubclass(ClassVar[int], int) assert generic_check_issubclass(TypeVar("T", int, float), (int, float)) assert generic_check_issubclass(TypeVar("T", bound=int), (int, float)) def test_is_coroutine_callable(): async def test1(): ... def test2(): ... class TestClass1: async def __call__(self): ... class TestClass2: def __call__(self): ... assert is_coroutine_callable(test1) assert not is_coroutine_callable(test2) assert not is_coroutine_callable(TestClass1) assert is_coroutine_callable(TestClass1()) assert not is_coroutine_callable(TestClass2) def test_is_gen_callable(): def test1(): yield async def test2(): yield def test3(): ... class TestClass1: def __call__(self): yield class TestClass2: async def __call__(self): yield class TestClass3: def __call__(self): ... assert is_gen_callable(test1) assert not is_gen_callable(test2) assert not is_gen_callable(test3) assert is_gen_callable(TestClass1()) assert not is_gen_callable(TestClass2()) assert not is_gen_callable(TestClass3()) def test_is_async_gen_callable(): async def test1(): yield def test2(): yield async def test3(): ... class TestClass1: async def __call__(self): yield class TestClass2: def __call__(self): yield class TestClass3: async def __call__(self): ... assert is_async_gen_callable(test1) assert not is_async_gen_callable(test2) assert not is_async_gen_callable(test3) assert is_async_gen_callable(TestClass1()) assert not is_async_gen_callable(TestClass2()) assert not is_async_gen_callable(TestClass3()) def test_dataclass_encoder(): simple = json.dumps("123", cls=DataclassEncoder) assert simple == '"123"' ms = FakeMessageSegment.nested(FakeMessage(FakeMessageSegment.text("text"))) s = json.dumps(ms, cls=DataclassEncoder) assert s == ( "{" '"type": "node", ' '"data": {"content": [{"type": "text", "data": {"text": "text"}}]}' "}" )