Skip to content

Commit 9426e2b

Browse files
bryanforbesfantix
andauthored
Add typings (MagicStack#366)
* Add typings and mypy test case * Update flake8 * Rename test class Co-authored-by: Fantix King <[email protected]>
1 parent fe3d028 commit 9426e2b

File tree

10 files changed

+357
-13
lines changed

10 files changed

+357
-13
lines changed

.flake8

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
[flake8]
2-
filename = *.py,*.pyx,*.pxd,*.pxi
2+
filename = *.py,*.pyx,*.pxd,*.pxi,*.pyi
33
ignore = E402,E731,D100,D101,D102,D103,D104,D105,W503,W504,E252
44
exclude = .git,__pycache__,build,dist,.eggs,postgres,vendor
55

6-
per-file-ignores = *.pyx,*.pxd,*.pxi: E211, E222, E225, E226, E227, E999
6+
per-file-ignores =
7+
*.pyx,*.pxd,*.pxi: E211, E222, E225, E226, E227, E999
8+
*.pyi: F401, F403, F405, F811, E127, E128, E203, E266, E301, E302, E305, E501, E701, E704, E741, B303, W503, W504

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,4 @@ uvloop/loop.*.pyd
3232
/.mypy_cache/
3333
/.vscode
3434
/.eggs
35+
/.venv*

MANIFEST.in

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
recursive-include docs *.py *.rst
22
recursive-include examples *.py
33
recursive-include tests *.py *.pem
4-
recursive-include uvloop *.pyx *.pxd *.pxi *.py *.c *.h
4+
recursive-include uvloop *.pyx *.pxd *.pxi *.py *.c *.h *.pyi py.typed
55
recursive-include vendor/libuv *
66
recursive-exclude vendor/libuv/.git *
77
recursive-exclude vendor/libuv/docs *
88
recursive-exclude vendor/libuv/img *
9-
include LICENSE-MIT LICENSE-APACHE README.rst Makefile performance.png .flake8
9+
include LICENSE-MIT LICENSE-APACHE README.rst Makefile performance.png .flake8 mypy.ini

mypy.ini

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[mypy]
2+
incremental = True
3+
strict = True
4+
5+
[mypy-uvloop._testbase]
6+
ignore_errors = True

setup.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,11 @@
2929
# their combination breaks too often
3030
# (example breakage: https://gitlab.com/pycqa/flake8/issues/427)
3131
'aiohttp',
32-
'flake8~=3.7.9',
32+
'flake8~=3.8.4',
3333
'psutil',
34-
'pycodestyle~=2.5.0',
35-
'pyOpenSSL~=19.0.0'
34+
'pycodestyle~=2.6.0',
35+
'pyOpenSSL~=19.0.0',
36+
'mypy>=0.800',
3637
]
3738

3839
# Dependencies required to build documentation.

tests/test_sourcecode.py

+32-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ def find_uvloop_root():
88
return os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
99

1010

11-
class TestFlake8(unittest.TestCase):
11+
class TestSourceCode(unittest.TestCase):
1212

1313
def test_flake8(self):
1414
edgepath = find_uvloop_root()
@@ -33,3 +33,34 @@ def test_flake8(self):
3333
output = ex.output.decode()
3434
raise AssertionError(
3535
'flake8 validation failed:\n{}'.format(output)) from None
36+
37+
def test_mypy(self):
38+
edgepath = find_uvloop_root()
39+
config_path = os.path.join(edgepath, 'mypy.ini')
40+
if not os.path.exists(config_path):
41+
raise RuntimeError('could not locate mypy.ini file')
42+
43+
try:
44+
import mypy # NoQA
45+
except ImportError:
46+
raise unittest.SkipTest('mypy moudule is missing')
47+
48+
try:
49+
subprocess.run(
50+
[
51+
sys.executable,
52+
'-m',
53+
'mypy',
54+
'--config-file',
55+
config_path,
56+
'uvloop'
57+
],
58+
check=True,
59+
stdout=subprocess.PIPE,
60+
stderr=subprocess.PIPE,
61+
cwd=edgepath
62+
)
63+
except subprocess.CalledProcessError as ex:
64+
output = ex.output.decode()
65+
raise AssertionError(
66+
'mypy validation failed:\n{}'.format(output)) from None

uvloop/__init__.py

+18-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import asyncio as __asyncio
2+
import typing as _typing
23

34
from asyncio.events import BaseDefaultEventLoopPolicy as __BasePolicy
45

@@ -10,16 +11,16 @@
1011
__all__ = ('new_event_loop', 'install', 'EventLoopPolicy')
1112

1213

13-
class Loop(__BaseLoop, __asyncio.AbstractEventLoop):
14+
class Loop(__BaseLoop, __asyncio.AbstractEventLoop): # type: ignore[misc]
1415
pass
1516

1617

17-
def new_event_loop():
18+
def new_event_loop() -> Loop:
1819
"""Return a new event loop."""
1920
return Loop()
2021

2122

22-
def install():
23+
def install() -> None:
2324
"""A helper function to install uvloop policy."""
2425
__asyncio.set_event_loop_policy(EventLoopPolicy())
2526

@@ -36,5 +37,18 @@ class EventLoopPolicy(__BasePolicy):
3637
<uvloop.Loop running=False closed=False debug=False>
3738
"""
3839

39-
def _loop_factory(self):
40+
def _loop_factory(self) -> Loop:
4041
return new_event_loop()
42+
43+
if _typing.TYPE_CHECKING:
44+
# EventLoopPolicy doesn't implement these, but since they are marked
45+
# as abstract in typeshed, we have to put them in so mypy thinks
46+
# the base methods are overridden. This is the same approach taken
47+
# for the Windows event loop policy classes in typeshed.
48+
def get_child_watcher(self) -> _typing.NoReturn:
49+
...
50+
51+
def set_child_watcher(
52+
self, watcher: _typing.Any
53+
) -> _typing.NoReturn:
54+
...

uvloop/_noop.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
def noop():
1+
def noop() -> None:
22
"""Empty function to invoke CPython ceval loop."""
33
return

0 commit comments

Comments
 (0)