Skip to content

Commit

Permalink
thoroughly fixed all typing issues for both mypy and pyright and remo…
Browse files Browse the repository at this point in the history
…ved all type ignores
  • Loading branch information
wolph committed Sep 25, 2024
1 parent 7ef8b42 commit 8fc4ffa
Show file tree
Hide file tree
Showing 18 changed files with 338 additions and 150 deletions.
16 changes: 8 additions & 8 deletions _python_utils_tests/test_aio.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@


@pytest.mark.asyncio
async def test_acount(monkeypatch: pytest.MonkeyPatch):
async def test_acount(monkeypatch: pytest.MonkeyPatch) -> None:
sleeps: types.List[float] = []

async def mock_sleep(delay: float):
async def mock_sleep(delay: float) -> None:
sleeps.append(delay)

monkeypatch.setattr(asyncio, 'sleep', mock_sleep)
Expand All @@ -23,13 +23,13 @@ async def mock_sleep(delay: float):


@pytest.mark.asyncio
async def test_acontainer():
async def async_gen():
async def test_acontainer() -> None:
async def async_gen() -> types.AsyncIterable[int]:
yield 1
yield 2
yield 3

async def empty_gen():
async def empty_gen() -> types.AsyncIterable[int]:
if False:
yield 1

Expand All @@ -52,13 +52,13 @@ async def empty_gen():


@pytest.mark.asyncio
async def test_adict():
async def async_gen():
async def test_adict() -> None:
async def async_gen() -> types.AsyncIterable[types.Tuple[int, int]]:
yield 1, 2
yield 3, 4
yield 5, 6

async def empty_gen():
async def empty_gen() -> types.AsyncIterable[types.Tuple[int, int]]:
if False:
yield 1, 2

Expand Down
31 changes: 17 additions & 14 deletions _python_utils_tests/test_decorators.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import typing
from unittest.mock import MagicMock

import pytest

from python_utils.decorators import sample, wraps_classmethod

T = typing.TypeVar('T')


@pytest.fixture
def random(monkeypatch: pytest.MonkeyPatch) -> MagicMock:
Expand All @@ -14,7 +17,7 @@ def random(monkeypatch: pytest.MonkeyPatch) -> MagicMock:
return mock


def test_sample_called(random: MagicMock):
def test_sample_called(random: MagicMock) -> None:
demo_function = MagicMock()
decorated = sample(0.5)(demo_function)
random.return_value = 0.4
Expand All @@ -28,7 +31,7 @@ def test_sample_called(random: MagicMock):
assert demo_function.call_count == 3


def test_sample_not_called(random: MagicMock):
def test_sample_not_called(random: MagicMock) -> None:
demo_function = MagicMock()
decorated = sample(0.5)(demo_function)
random.return_value = 0.5
Expand All @@ -40,31 +43,31 @@ def test_sample_not_called(random: MagicMock):

class SomeClass:
@classmethod
def some_classmethod(cls, arg): # type: ignore
return arg # type: ignore
def some_classmethod(cls, arg: T) -> T:
return arg

@classmethod
def some_annotated_classmethod(cls, arg: int) -> int:
return arg


def test_wraps_classmethod(): # type: ignore
def test_wraps_classmethod() -> None:
some_class = SomeClass()
some_class.some_classmethod = MagicMock()
wrapped_method = wraps_classmethod( # type: ignore
SomeClass.some_classmethod # type: ignore
)( # type: ignore
some_class.some_classmethod # type: ignore
some_class.some_classmethod = MagicMock() # type: ignore[method-assign]
wrapped_method = wraps_classmethod(
SomeClass.some_classmethod
)(
some_class.some_classmethod
)
wrapped_method(123)
some_class.some_classmethod.assert_called_with(123) # type: ignore
some_class.some_classmethod.assert_called_with(123)


def test_wraps_annotated_classmethod(): # type: ignore
def test_wraps_annotated_classmethod() -> None:
some_class = SomeClass()
some_class.some_annotated_classmethod = MagicMock()
some_class.some_annotated_classmethod = MagicMock() # type: ignore[method-assign]
wrapped_method = wraps_classmethod(SomeClass.some_annotated_classmethod)(
some_class.some_annotated_classmethod
)
wrapped_method(123) # type: ignore
wrapped_method(123)
some_class.some_annotated_classmethod.assert_called_with(123)
8 changes: 4 additions & 4 deletions _python_utils_tests/test_generators.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@


@pytest.mark.asyncio
async def test_abatcher():
async def test_abatcher() -> None:
async for batch in python_utils.abatcher(python_utils.acount(stop=9), 3):
assert len(batch) == 3

Expand All @@ -28,8 +28,8 @@ async def test_abatcher_timed() -> None:


@pytest.mark.asyncio
async def test_abatcher_timed_with_timeout():
async def generator():
async def test_abatcher_timed_with_timeout() -> None:
async def generator() -> types.AsyncIterator[int]:
# Test if the timeout is respected
yield 0
yield 1
Expand Down Expand Up @@ -57,7 +57,7 @@ async def generator():
await batcher.__anext__()


def test_batcher():
def test_batcher() -> None:
batch = []
for batch in python_utils.batcher(range(9), 3):
assert len(batch) == 3
Expand Down
14 changes: 7 additions & 7 deletions _python_utils_tests/test_import.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
from python_utils import import_, types


def test_import_globals_relative_import():
def test_import_globals_relative_import() -> None:
for i in range(-1, 5):
relative_import(i)


def relative_import(level: int):
def relative_import(level: int) -> None:
locals_: types.Dict[str, types.Any] = {}
globals_ = {'__name__': 'python_utils.import_'}
import_.import_global('.formatters', locals_=locals_, globals_=globals_)
assert 'camel_to_underscore' in globals_


def test_import_globals_without_inspection():
def test_import_globals_without_inspection() -> None:
locals_: types.Dict[str, types.Any] = {}
globals_: types.Dict[str, types.Any] = {'__name__': __name__}
import_.import_global(
Expand All @@ -22,7 +22,7 @@ def test_import_globals_without_inspection():
assert 'camel_to_underscore' in globals_


def test_import_globals_single_method():
def test_import_globals_single_method() -> None:
locals_: types.Dict[str, types.Any] = {}
globals_: types.Dict[str, types.Any] = {'__name__': __name__}
import_.import_global(
Expand All @@ -34,19 +34,19 @@ def test_import_globals_single_method():
assert 'camel_to_underscore' in globals_


def test_import_globals_with_inspection():
def test_import_globals_with_inspection() -> None:
import_.import_global('python_utils.formatters')
assert 'camel_to_underscore' in globals()


def test_import_globals_missing_module():
def test_import_globals_missing_module() -> None:
import_.import_global(
'python_utils.spam', exceptions=ImportError, locals_=locals()
)
assert 'camel_to_underscore' in globals()


def test_import_locals_missing_module():
def test_import_locals_missing_module() -> None:
import_.import_global(
'python_utils.spam', exceptions=ImportError, globals_=globals()
)
Expand Down
3 changes: 2 additions & 1 deletion _python_utils_tests/test_logger.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
# mypy: disable-error-code=misc
import pytest

from python_utils.loguru import Logurud

loguru = pytest.importorskip('loguru')


def test_logurud():
def test_logurud() -> None:
class MyClass(Logurud):
pass

Expand Down
2 changes: 1 addition & 1 deletion _python_utils_tests/test_python_utils.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from python_utils import __about__


def test_definitions():
def test_definitions() -> None:
# The setup.py requires this so we better make sure they exist :)
assert __about__.__version__
assert __about__.__author__
Expand Down
28 changes: 14 additions & 14 deletions _python_utils_tests/test_time.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ async def test_aio_timeout_generator(
maximum_interval: float,
iterable: types.AsyncIterable[types.Any],
result: int,
):
) -> None:
i = None
async for i in python_utils.aio_timeout_generator(
timeout, interval, iterable, maximum_interval=maximum_interval
Expand All @@ -46,15 +46,15 @@ async def test_aio_timeout_generator(
'timeout,interval,interval_multiplier,maximum_interval,iterable,result',
[
(0.01, 0.006, 0.5, 0.01, 'abc', 'c'),
(0.01, 0.006, 0.5, 0.01, itertools.count, 2), # type: ignore
(0.01, 0.006, 0.5, 0.01, itertools.count, 2),
(0.01, 0.006, 0.5, 0.01, itertools.count(), 2),
(0.01, 0.006, 1.0, None, 'abc', 'c'),
(
timedelta(seconds=0.01),
timedelta(seconds=0.006),
2.0,
timedelta(seconds=0.01),
itertools.count, # type: ignore
itertools.count,
2,
),
],
Expand All @@ -70,7 +70,7 @@ def test_timeout_generator(
types.Callable[..., types.Iterable[types.Any]],
],
result: int,
):
) -> None:
i = None
for i in python_utils.timeout_generator(
timeout=timeout,
Expand All @@ -85,11 +85,11 @@ def test_timeout_generator(


@pytest.mark.asyncio
async def test_aio_generator_timeout_detector():
async def test_aio_generator_timeout_detector() -> None:
# Make pyright happy
i = None

async def generator():
async def generator() -> types.AsyncGenerator[int, None]:
for i in range(10):
await asyncio.sleep(i / 100.0)
yield i
Expand Down Expand Up @@ -123,10 +123,10 @@ async def generator():


@pytest.mark.asyncio
async def test_aio_generator_timeout_detector_decorator_reraise():
async def test_aio_generator_timeout_detector_decorator_reraise() -> None:
# Test regular timeout with reraise
@python_utils.aio_generator_timeout_detector_decorator(timeout=0.05)
async def generator_timeout():
async def generator_timeout() -> types.AsyncGenerator[int, None]:
for i in range(10):
await asyncio.sleep(i / 100.0)
yield i
Expand All @@ -137,15 +137,15 @@ async def generator_timeout():


@pytest.mark.asyncio
async def test_aio_generator_timeout_detector_decorator_clean_exit():
async def test_aio_generator_timeout_detector_decorator_clean_exit() -> None:
# Make pyright happy
i = None

# Test regular timeout with clean exit
@python_utils.aio_generator_timeout_detector_decorator(
timeout=0.05, on_timeout=None
)
async def generator_clean():
async def generator_clean() -> types.AsyncGenerator[int, None]:
for i in range(10):
await asyncio.sleep(i / 100.0)
yield i
Expand All @@ -157,10 +157,10 @@ async def generator_clean():


@pytest.mark.asyncio
async def test_aio_generator_timeout_detector_decorator_reraise_total():
async def test_aio_generator_timeout_detector_decorator_reraise_total() -> None:

Check failure on line 160 in _python_utils_tests/test_time.py

View workflow job for this annotation

GitHub Actions / docs_and_lint

Ruff (E501)

_python_utils_tests/test_time.py:160:80: E501 Line too long (80 > 79)

Check failure on line 160 in _python_utils_tests/test_time.py

View workflow job for this annotation

GitHub Actions / build (3.10)

Ruff (E501)

_python_utils_tests/test_time.py:160:80: E501 Line too long (80 > 79)

Check failure on line 160 in _python_utils_tests/test_time.py

View workflow job for this annotation

GitHub Actions / build (3.11)

Ruff (E501)

_python_utils_tests/test_time.py:160:80: E501 Line too long (80 > 79)
# Test total timeout with reraise
@python_utils.aio_generator_timeout_detector_decorator(total_timeout=0.1)
async def generator_reraise():
async def generator_reraise() -> types.AsyncGenerator[int, None]:
for i in range(10):
await asyncio.sleep(i / 100.0)
yield i
Expand All @@ -171,15 +171,15 @@ async def generator_reraise():


@pytest.mark.asyncio
async def test_aio_generator_timeout_detector_decorator_clean_total():
async def test_aio_generator_timeout_detector_decorator_clean_total() -> None:
# Make pyright happy
i = None

# Test total timeout with clean exit
@python_utils.aio_generator_timeout_detector_decorator(
total_timeout=0.1, on_timeout=None
)
async def generator_clean_total():
async def generator_clean_total() -> types.AsyncGenerator[int, None]:
for i in range(10):
await asyncio.sleep(i / 100.0)
yield i
Expand Down
6 changes: 6 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,9 @@ strict = ['python_utils', '_python_utils_tests', 'setup.py']
ignore = ['python_utils/terminal.py']
pythonVersion = '3.9'

[tool.mypy]
strict = true
check_untyped_defs = true

[[tool.mypy.overrides]]
module = '_python_utils_tests.*'
5 changes: 3 additions & 2 deletions python_utils/aio.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,9 @@ async def acontainer(
types.AsyncIterable[_T],
types.Callable[..., types.AsyncIterable[_T]],
],
container: types.Callable[[types.Iterable[_T]], types.Iterable[_T]] = list,
) -> types.Iterable[_T]:
container: types.Callable[[types.Iterable[_T]], types.Collection[_T]] =
list,
) -> types.Collection[_T]:
"""
Asyncio version of list()/set()/tuple()/etc() using an async for loop.
Expand Down
Loading

0 comments on commit 8fc4ffa

Please sign in to comment.