diff options
-rw-r--r-- | .mypy.ini | 14 | ||||
-rw-r--r-- | fietsboek/config.py | 2 | ||||
-rw-r--r-- | fietsboek/pages.py | 15 | ||||
-rw-r--r-- | fietsboek/updater/__init__.py | 8 | ||||
-rw-r--r-- | fietsboek/util.py | 2 | ||||
-rw-r--r-- | fietsboek/views/browse.py | 5 | ||||
-rw-r--r-- | fietsboek/views/tileproxy.py | 4 | ||||
-rw-r--r-- | tox.ini | 14 |
8 files changed, 48 insertions, 16 deletions
diff --git a/.mypy.ini b/.mypy.ini new file mode 100644 index 0000000..79f0c44 --- /dev/null +++ b/.mypy.ini @@ -0,0 +1,14 @@ +[mypy] +follow_imports = silent +check_untyped_defs = True +allow_redefinition = True +exclude = fietsboek/updater/scripts/.+\.py + +[mypy-pyramid.*] +ignore_missing_imports = True + +[mypy-sqlalchemy.*] +ignore_missing_imports = True + +[mypy-zope.*] +ignore_missing_imports = True diff --git a/fietsboek/config.py b/fietsboek/config.py index 05fd4f6..74dc4d8 100644 --- a/fietsboek/config.py +++ b/fietsboek/config.py @@ -142,7 +142,7 @@ class Config(BaseModel): session_key: str """Session key.""" - available_locales: PyramidList = ["en", "de"] + available_locales: PyramidList = PyramidList(["en", "de"]) """Available locales.""" email_from: str = Field(alias="email.from") diff --git a/fietsboek/pages.py b/fietsboek/pages.py index e94a493..d8fd859 100644 --- a/fietsboek/pages.py +++ b/fietsboek/pages.py @@ -1,6 +1,7 @@ """Module containing logic to support "static" pages.""" import enum import re +from typing import List, Optional import markdown @@ -91,20 +92,21 @@ class Page: parser = markdown.Markdown(extensions=["meta"]) content = parser.convert(text) - title = parser.Meta.get('title', [''])[0] + title = parser.Meta.get('title', [''])[0] # type: ignore if not title: raise PageException("Missing `title`") - link_name = parser.Meta.get('link-name', [''])[0] + link_name = parser.Meta.get('link-name', [''])[0] # type: ignore if not link_name: raise PageException("Missing `link-name`") - slug = parser.Meta.get('slug', [''])[0] + slug = parser.Meta.get('slug', [''])[0] # type: ignore if not slug: raise PageException("Missing `slug`") + locale_filter: Optional[List[re.Pattern]] try: - locale_filter = list(map(re.compile, parser.Meta.get('locale', []))) + locale_filter = list(map(re.compile, parser.Meta.get('locale', []))) # type: ignore except re.error as exc: raise PageException("Invalid locale regex") from exc if not locale_filter: @@ -115,12 +117,13 @@ class Page: 'logged-out': UserFilter.LOGGED_OUT, 'everyone': UserFilter.EVERYONE, } - user_filter = filter_map.get(parser.Meta.get('show-to', ['everyone'])[0].lower()) + user_filter = filter_map.get( + parser.Meta.get('show-to', ['everyone'])[0].lower()) # type: ignore if user_filter is None: raise PageException("Invalid `show-to` filter") try: - menu_index = int(parser.Meta.get('index', ['0'])[0]) + menu_index = int(parser.Meta.get('index', ['0'])[0]) # type: ignore except ValueError as exc: raise PageException("Invalid value for `index`") from exc diff --git a/fietsboek/updater/__init__.py b/fietsboek/updater/__init__.py index a5bcf0e..d336daf 100644 --- a/fietsboek/updater/__init__.py +++ b/fietsboek/updater/__init__.py @@ -5,6 +5,7 @@ import random import string import importlib.util from pathlib import Path +from typing import List # Compat for Python < 3.9 import importlib_resources @@ -151,7 +152,7 @@ class Updater: def _make_schedule(self, wanted, dependencies): wanted = set(wanted) - queue = [] + queue: List[str] = [] while wanted: next_updates = { update @@ -233,7 +234,7 @@ class Updater: current_alembic = context.get_current_heads() LOGGER.debug("Found alembic versions: %s", current_alembic) assert len(current_alembic) == 1 - current_alembic = current_alembic[0] + current_alembic = current_alembic[0] # type: ignore loader = jinja2.DictLoader({"revision.py": TEMPLATE}) env = jinja2.Environment(loader=loader, autoescape=False) @@ -291,7 +292,8 @@ class UpdateScript: def __init__(self, source, name): self.name = name spec = importlib.util.spec_from_loader(f"{__name__}.{name}", None) - self.module = importlib.util.module_from_spec(spec) + self.module = importlib.util.module_from_spec(spec) # type: ignore + assert self.module exec(source, self.module.__dict__) # pylint: disable=exec-used def __repr__(self): diff --git a/fietsboek/util.py b/fietsboek/util.py index 71f5d16..a500d1e 100644 --- a/fietsboek/util.py +++ b/fietsboek/util.py @@ -58,7 +58,7 @@ def safe_markdown(md_source): :return: The safe HTML transformed version. :rtype: Markup """ - html = markdown.markdown(md_source, output_format='html5') + html = markdown.markdown(md_source, output_format='html') html = bleach.clean(html, tags=ALLOWED_TAGS, attributes=ALLOWED_ATTRIBUTES) return Markup(html) diff --git a/fietsboek/views/browse.py b/fietsboek/views/browse.py index c01d4f6..986ae5e 100644 --- a/fietsboek/views/browse.py +++ b/fietsboek/views/browse.py @@ -1,6 +1,7 @@ """Views for browsing all tracks.""" import datetime from io import RawIOBase +from typing import List from zipfile import ZipFile, ZIP_DEFLATED from pyramid.view import view_config @@ -212,7 +213,7 @@ class FilterCollection(Filter): :rtype: FilterCollection """ # pylint: disable=singleton-comparison - filters = [] + filters: List[Filter] = [] if request.params.get('search-terms'): term = request.params.get('search-terms').strip() filters.append(SearchFilter([term])) @@ -341,7 +342,7 @@ def archive(request): def generate(): try: stream = Stream() - with ZipFile(stream, "w", ZIP_DEFLATED) as zipfile: + with ZipFile(stream, "w", ZIP_DEFLATED) as zipfile: # type: ignore for track in tracks: zipfile.writestr(f"track_{track.id}.gpx", track.gpx_data) yield stream.readall() diff --git a/fietsboek/views/tileproxy.py b/fietsboek/views/tileproxy.py index 3e2abc1..f484caf 100644 --- a/fietsboek/views/tileproxy.py +++ b/fietsboek/views/tileproxy.py @@ -9,7 +9,7 @@ Additionally, this protects the users' IP, as only fietsboek can see it. import datetime import random import logging -from typing import NamedTuple +from typing import NamedTuple, Optional from itertools import chain from pyramid.view import view_config @@ -33,7 +33,7 @@ class TileSource(NamedTuple): """URL with placeholders.""" layer_type: LayerType """Type of this layer.""" - zoom: int + zoom: Optional[int] """Max zoom of this layer.""" access: LayerAccess """Access restrictions to use this layer.""" @@ -5,7 +5,7 @@ per-file-ignores = fietsboek/models/__init__.py:F401 [tox] -envlist = python,pylint,pylint-tests,flake8 +envlist = python,pylint,pylint-tests,flake8,mypy isolated_build = true [testenv] @@ -44,3 +44,15 @@ allowlist_externals = make changedir={toxinidir}{/}doc commands = make html + +[testenv:mypy] +deps = + mypy + types-Markdown + types-bleach + types-babel + types-redis + types-requests +usedevelop = true +commands = + mypy fietsboek |