lk-geimfari / mimesis

Mimesis is a robust data generator for Python that can produce a wide range of fake data in multiple languages.
https://mimesis.name
MIT License
4.34k stars 326 forks source link

Fix type hints for key functions and field handlers #1521

Closed mheguy-flo closed 2 months ago

mheguy-flo commented 3 months ago

I have made things!

Good: This removes the need to add type ignores when registering new handlers. Bad: This allows basically any function. It is the equivalent of using Any.

Of the two bad options, it is better to not force devs to add type ignores.

Alternative considered: I tried implementing a protocol. Neither mypy nor pyright properly handled all cases.

Checklist

Attempt with protocol

from contextlib import nullcontext as does_not_raise
from random import Random
from typing import Any, Protocol
import pytest
from mimesis.schema import Field
class FieldHandler(Protocol):
    def __call__(self, random: Random, **kwargs: Any) -> Any: ...
    __name__: str
@pytest.fixture(name="field", scope="module")
def field_fixture() -> Field:
    return Field()
def use_handler(field: FieldHandler) -> None:
    field(Random(), kwarg1=1, kwarg2=2, bloop=0)
def test_handler_type_hint_passing_cases(field: Field) -> None:
    def no_keyword_args(random: Random, **kwargs: Any) -> Any: ...
    use_handler(no_keyword_args)
    def with_kwarg(random: Random, *, kwarg1: int, **kwargs: Any) -> Any: ...
    use_handler(with_kwarg)  # type: ignore # mypy false positive
    def kwarg_with_default(random: Random, kwarg1: int = 0, **kwargs: Any) -> Any: ...
    use_handler(kwarg_with_default)
def test_handler_type_hint_failing_cases(field: Field) -> None:
    def missing_positional_arg(**kwargs: Any) -> Any: ...
    with pytest.raises(TypeError):
        use_handler(missing_positional_arg)  # type: ignore
    def positional_arg_wrong_type(not_random: int, **kwargs: Any) -> Any: ...
    with does_not_raise():
        use_handler(positional_arg_wrong_type)  # type: ignore
    def missing_kwargs(random: Random) -> Any: ...
    with pytest.raises(TypeError):
        use_handler(missing_kwargs)  # type: ignore
    def extra_positional_arg(random: Random, extra_arg: int, **kwargs: Any) -> Any: ...
    with pytest.raises(TypeError):
        use_handler(extra_positional_arg)  # type: ignore # pyright false negative
codecov[bot] commented 3 months ago

Codecov Report

Merging #1521 (2448633) into master (95a1d70) will decrease coverage by 0.05%. The diff coverage is 50.00%.

Additional details and impacted files ```diff @@ Coverage Diff @@ ## master #1521 +/- ## ========================================== - Coverage 57.08% 57.04% -0.05% ========================================== Files 60 60 Lines 2123 2123 ========================================== - Hits 1212 1211 -1 - Misses 911 912 +1 ```