Enable static type checking

This commit is contained in:
Unrud 2020-10-04 15:13:01 +02:00 committed by Unrud
parent 34bec01c9b
commit 73e42f8101
9 changed files with 36 additions and 7 deletions

1
.gitignore vendored
View File

@ -15,6 +15,7 @@ coverage.xml
.coverage .coverage
.coverage.* .coverage.*
.eggs .eggs
.mypy_cache
.project .project
.pydevproject .pydevproject
.settings .settings

View File

@ -58,7 +58,7 @@ from radicale.log import logger
# WORKAROUND: https://github.com/tiran/defusedxml/issues/54 # WORKAROUND: https://github.com/tiran/defusedxml/issues/54
import defusedxml.ElementTree as DefusedET # isort: skip import defusedxml.ElementTree as DefusedET # isort: skip
sys.modules["xml.etree"].ElementTree = ET sys.modules["xml.etree"].ElementTree = ET # type: ignore[attr-defined]
VERSION = pkg_resources.get_distribution("radicale").version VERSION = pkg_resources.get_distribution("radicale").version

View File

@ -31,6 +31,7 @@ import os
import string import string
from collections import OrderedDict from collections import OrderedDict
from configparser import RawConfigParser from configparser import RawConfigParser
from typing import Any, ClassVar
from radicale import auth, rights, storage, web from radicale import auth, rights, storage, web
@ -285,7 +286,7 @@ def load(paths=()):
class Configuration: class Configuration:
SOURCE_MISSING = {} SOURCE_MISSING: ClassVar[Any] = {}
def __init__(self, schema): def __init__(self, schema):
"""Initialize configuration. """Initialize configuration.

View File

@ -27,6 +27,7 @@ import posixpath
import sys import sys
import threading import threading
from tempfile import TemporaryDirectory from tempfile import TemporaryDirectory
from typing import Type, Union
if os.name == "nt": if os.name == "nt":
import ctypes import ctypes
@ -34,6 +35,7 @@ if os.name == "nt":
import msvcrt import msvcrt
LOCKFILE_EXCLUSIVE_LOCK = 2 LOCKFILE_EXCLUSIVE_LOCK = 2
ULONG_PTR: Union[Type[ctypes.c_uint32], Type[ctypes.c_uint64]]
if ctypes.sizeof(ctypes.c_void_p) == 4: if ctypes.sizeof(ctypes.c_void_p) == 4:
ULONG_PTR = ctypes.c_uint32 ULONG_PTR = ctypes.c_uint32
else: else:
@ -47,7 +49,8 @@ if os.name == "nt":
("offset_high", ctypes.wintypes.DWORD), ("offset_high", ctypes.wintypes.DWORD),
("h_event", ctypes.wintypes.HANDLE)] ("h_event", ctypes.wintypes.HANDLE)]
kernel32 = ctypes.WinDLL("kernel32", use_last_error=True) kernel32 = ctypes.WinDLL( # type: ignore[attr-defined]
"kernel32", use_last_error=True)
lock_file_ex = kernel32.LockFileEx lock_file_ex = kernel32.LockFileEx
lock_file_ex.argtypes = [ lock_file_ex.argtypes = [
ctypes.wintypes.HANDLE, ctypes.wintypes.HANDLE,

View File

@ -30,21 +30,25 @@ import socketserver
import ssl import ssl
import sys import sys
import wsgiref.simple_server import wsgiref.simple_server
from typing import MutableMapping
from urllib.parse import unquote from urllib.parse import unquote
from radicale import Application, config from radicale import Application, config
from radicale.log import logger from radicale.log import logger
COMPAT_EAI_ADDRFAMILY: int
if hasattr(socket, "EAI_ADDRFAMILY"): if hasattr(socket, "EAI_ADDRFAMILY"):
COMPAT_EAI_ADDRFAMILY = socket.EAI_ADDRFAMILY COMPAT_EAI_ADDRFAMILY = socket.EAI_ADDRFAMILY # type: ignore[attr-defined]
elif hasattr(socket, "EAI_NONAME"): elif hasattr(socket, "EAI_NONAME"):
# Windows and BSD don't have a special error code for this # Windows and BSD don't have a special error code for this
COMPAT_EAI_ADDRFAMILY = socket.EAI_NONAME COMPAT_EAI_ADDRFAMILY = socket.EAI_NONAME
COMPAT_EAI_NODATA: int
if hasattr(socket, "EAI_NODATA"): if hasattr(socket, "EAI_NODATA"):
COMPAT_EAI_NODATA = socket.EAI_NODATA COMPAT_EAI_NODATA = socket.EAI_NODATA
elif hasattr(socket, "EAI_NONAME"): elif hasattr(socket, "EAI_NONAME"):
# Windows and BSD don't have a special error code for this # Windows and BSD don't have a special error code for this
COMPAT_EAI_NODATA = socket.EAI_NONAME COMPAT_EAI_NODATA = socket.EAI_NONAME
COMPAT_IPPROTO_IPV6: int
if hasattr(socket, "IPPROTO_IPV6"): if hasattr(socket, "IPPROTO_IPV6"):
COMPAT_IPPROTO_IPV6 = socket.IPPROTO_IPV6 COMPAT_IPPROTO_IPV6 = socket.IPPROTO_IPV6
elif os.name == "nt": elif os.name == "nt":
@ -155,7 +159,7 @@ class ParallelHTTPSServer(ParallelHTTPServer):
class ServerHandler(wsgiref.simple_server.ServerHandler): class ServerHandler(wsgiref.simple_server.ServerHandler):
# Don't pollute WSGI environ with OS environment # Don't pollute WSGI environ with OS environment
os_environ = {} os_environ: MutableMapping[str, str] = {}
def log_exception(self, exc_info): def log_exception(self, exc_info):
logger.error("An exception occurred during request: %s", logger.error("An exception occurred during request: %s",

View File

@ -25,6 +25,7 @@ import posixpath
import shutil import shutil
import sys import sys
import tempfile import tempfile
from typing import Any, ClassVar
import defusedxml.ElementTree as DefusedET import defusedxml.ElementTree as DefusedET
import pytest import pytest
@ -1549,7 +1550,8 @@ class BaseRequestsMixIn:
class BaseFileSystemTest(BaseTest): class BaseFileSystemTest(BaseTest):
"""Base class for filesystem backend tests.""" """Base class for filesystem backend tests."""
storage_type = None
storage_type: ClassVar[Any]
def setup(self): def setup(self):
self.configuration = config.load() self.configuration = config.load()

View File

@ -41,10 +41,17 @@ from radicale.tests.helpers import configuration_to_dict, get_file_path
class DisabledRedirectHandler(request.HTTPRedirectHandler): class DisabledRedirectHandler(request.HTTPRedirectHandler):
def http_error_301(self, req, fp, code, msg, headers):
raise HTTPError(req.full_url, code, msg, headers, fp)
def http_error_302(self, req, fp, code, msg, headers): def http_error_302(self, req, fp, code, msg, headers):
raise HTTPError(req.full_url, code, msg, headers, fp) raise HTTPError(req.full_url, code, msg, headers, fp)
http_error_301 = http_error_303 = http_error_307 = http_error_302 def http_error_303(self, req, fp, code, msg, headers):
raise HTTPError(req.full_url, code, msg, headers, fp)
def http_error_307(self, req, fp, code, msg, headers):
raise HTTPError(req.full_url, code, msg, headers, fp)
class TestBaseServerRequests(BaseTest): class TestBaseServerRequests(BaseTest):

View File

@ -5,6 +5,7 @@ test = pytest
python-tag = py3 python-tag = py3
[tool:pytest] [tool:pytest]
# More options are set in `setup.py` via environment variable `PYTEST_ADDOPTS`
addopts = --flake8 --isort --cov --cov-report=term --cov-report=xml -r s addopts = --flake8 --isort --cov --cov-report=term --cov-report=xml -r s
norecursedirs = dist .cache .git build Radicale.egg-info .eggs venv norecursedirs = dist .cache .git build Radicale.egg-info .eggs venv
@ -15,6 +16,10 @@ known_third_party = defusedxml,passlib,pkg_resources,pytest,vobject
[flake8] [flake8]
extend-ignore = H extend-ignore = H
[mypy]
ignore_missing_imports = True
show_error_codes = True
[coverage:run] [coverage:run]
branch = True branch = True
source = radicale source = radicale

View File

@ -36,6 +36,7 @@ For further information, please visit the `Radicale Website
""" """
import os
import sys import sys
from setuptools import find_packages, setup from setuptools import find_packages, setup
@ -52,6 +53,11 @@ needs_pytest = {"pytest", "test", "ptr"}.intersection(sys.argv)
pytest_runner = ["pytest-runner"] if needs_pytest else [] pytest_runner = ["pytest-runner"] if needs_pytest else []
tests_require = ["pytest-runner", "pytest", "pytest-cov", "pytest-flake8", tests_require = ["pytest-runner", "pytest", "pytest-cov", "pytest-flake8",
"pytest-isort", "waitress"] "pytest-isort", "waitress"]
os.environ["PYTEST_ADDOPTS"] = os.environ.get("PYTEST_ADDOPTS", "")
# Mypy only supports CPython
if sys.implementation.name == "cpython":
tests_require.extend(["pytest-mypy", "types-setuptools"])
os.environ["PYTEST_ADDOPTS"] += " --mypy"
setup( setup(
name="Radicale", name="Radicale",