Enable static type checking
This commit is contained in:
parent
34bec01c9b
commit
73e42f8101
1
.gitignore
vendored
1
.gitignore
vendored
@ -15,6 +15,7 @@ coverage.xml
|
|||||||
.coverage
|
.coverage
|
||||||
.coverage.*
|
.coverage.*
|
||||||
.eggs
|
.eggs
|
||||||
|
.mypy_cache
|
||||||
.project
|
.project
|
||||||
.pydevproject
|
.pydevproject
|
||||||
.settings
|
.settings
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
@ -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,
|
||||||
|
@ -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",
|
||||||
|
@ -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()
|
||||||
|
@ -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):
|
||||||
|
@ -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
|
||||||
|
6
setup.py
6
setup.py
@ -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",
|
||||||
|
Loading…
Reference in New Issue
Block a user