diff options
36 files changed, 141 insertions, 182 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 902d3fd..4905fc5 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -34,7 +34,7 @@ test-pypy:  lint:    script: -    - tox -e pylint,pylint-tests,flake,black +    - tox -e pylint,pylint-tests,flake,black,isort  mypy:    script: diff --git a/fietsboek/__init__.py b/fietsboek/__init__.py index d45e9d5..0e9399c 100644 --- a/fietsboek/__init__.py +++ b/fietsboek/__init__.py @@ -7,15 +7,15 @@ from pathlib import Path  import importlib_metadata  import redis  from pyramid.config import Configurator -from pyramid.session import SignedCookieSessionFactory  from pyramid.csrf import CookieCSRFStoragePolicy  from pyramid.i18n import default_locale_negotiator +from pyramid.session import SignedCookieSessionFactory -from .security import SecurityPolicy +from . import config as mod_config +from . import jinja2 as mod_jinja2  from .data import DataManager  from .pages import Pages -from . import jinja2 as mod_jinja2, config as mod_config - +from .security import SecurityPolicy  __VERSION__ = importlib_metadata.version("fietsboek") diff --git a/fietsboek/actions.py b/fietsboek/actions.py index dff512f..f1a32fc 100644 --- a/fietsboek/actions.py +++ b/fietsboek/actions.py @@ -15,9 +15,8 @@ from sqlalchemy import select  from sqlalchemy.orm.session import Session  from fietsboek import models, util -from fietsboek.models.track import Visibility, TrackType  from fietsboek.data import DataManager - +from fietsboek.models.track import TrackType, Visibility  LOGGER = logging.getLogger(__name__) diff --git a/fietsboek/alembic/versions/20220702_1b4b1c179e5a.py b/fietsboek/alembic/versions/20220702_1b4b1c179e5a.py index af6d73a..2759bd6 100644 --- a/fietsboek/alembic/versions/20220702_1b4b1c179e5a.py +++ b/fietsboek/alembic/versions/20220702_1b4b1c179e5a.py @@ -5,9 +5,8 @@ Revises:  Create Date: 2022-07-02 20:36:23.501403  """ -from alembic import op  import sqlalchemy as sa - +from alembic import op  # revision identifiers, used by Alembic.  revision = '1b4b1c179e5a' diff --git a/fietsboek/alembic/versions/20220706_c89d9bdbfa68.py b/fietsboek/alembic/versions/20220706_c89d9bdbfa68.py index 83b2978..2336348 100644 --- a/fietsboek/alembic/versions/20220706_c89d9bdbfa68.py +++ b/fietsboek/alembic/versions/20220706_c89d9bdbfa68.py @@ -5,9 +5,8 @@ Revises: 1b4b1c179e5a  Create Date: 2022-07-06 14:05:15.431716  """ -from alembic import op  import sqlalchemy as sa - +from alembic import op  # revision identifiers, used by Alembic.  revision = 'c89d9bdbfa68' diff --git a/fietsboek/alembic/versions/20220721_091ce24409fe.py b/fietsboek/alembic/versions/20220721_091ce24409fe.py index 88044b6..7b0d35d 100644 --- a/fietsboek/alembic/versions/20220721_091ce24409fe.py +++ b/fietsboek/alembic/versions/20220721_091ce24409fe.py @@ -5,9 +5,8 @@ Revises: c89d9bdbfa68  Create Date: 2022-07-21 23:24:54.241170  """ -from alembic import op  import sqlalchemy as sa - +from alembic import op  # revision identifiers, used by Alembic.  revision = '091ce24409fe' diff --git a/fietsboek/alembic/versions/20220808_d085998b49ca.py b/fietsboek/alembic/versions/20220808_d085998b49ca.py index 56dbbf7..d6353d2 100644 --- a/fietsboek/alembic/versions/20220808_d085998b49ca.py +++ b/fietsboek/alembic/versions/20220808_d085998b49ca.py @@ -5,9 +5,8 @@ Revises: 091ce24409fe  Create Date: 2022-08-08 14:11:40.746008  """ -from alembic import op  import sqlalchemy as sa - +from alembic import op  # revision identifiers, used by Alembic.  revision = 'd085998b49ca' diff --git a/fietsboek/alembic/versions/20221214_c939800af428.py b/fietsboek/alembic/versions/20221214_c939800af428.py index 4b07983..0fade88 100644 --- a/fietsboek/alembic/versions/20221214_c939800af428.py +++ b/fietsboek/alembic/versions/20221214_c939800af428.py @@ -5,10 +5,10 @@ Revises: d085998b49ca  Create Date: 2022-12-14 23:58:37.983942  """ -from alembic import op -import sqlalchemy as sa  import logging +import sqlalchemy as sa +from alembic import op  # revision identifiers, used by Alembic.  revision = 'c939800af428' diff --git a/fietsboek/config.py b/fietsboek/config.py index 9949198..068382e 100644 --- a/fietsboek/config.py +++ b/fietsboek/config.py @@ -20,14 +20,7 @@ import urllib.parse  from enum import Enum  import pydantic -from pydantic import ( -    BaseModel, -    Field, -    AnyUrl, -    DirectoryPath, -    validator, -    SecretStr, -) +from pydantic import AnyUrl, BaseModel, DirectoryPath, Field, SecretStr, validator  from pyramid import settings  from termcolor import colored diff --git a/fietsboek/data.py b/fietsboek/data.py index 6db8294..f32e24f 100644 --- a/fietsboek/data.py +++ b/fietsboek/data.py @@ -4,13 +4,13 @@ Data are objects that belong to a track (such as images), but are not stored in  the database itself. This module makes access to such data objects easier.  """  import datetime +import logging  import random -import string  import shutil +import string  import uuid -import logging -from typing import List, BinaryIO, Optional  from pathlib import Path +from typing import BinaryIO, List, Optional  import brotli  import gpxpy @@ -18,7 +18,6 @@ from filelock import FileLock  from .util import secure_filename -  LOGGER = logging.getLogger(__name__) diff --git a/fietsboek/email.py b/fietsboek/email.py index 78b0493..ee111a1 100644 --- a/fietsboek/email.py +++ b/fietsboek/email.py @@ -2,9 +2,8 @@  import logging  import smtplib  import sys - -from urllib.parse import urlparse  from email.message import EmailMessage +from urllib.parse import urlparse  LOGGER = logging.getLogger(__name__) diff --git a/fietsboek/jinja2.py b/fietsboek/jinja2.py index 07c9087..8330ea7 100644 --- a/fietsboek/jinja2.py +++ b/fietsboek/jinja2.py @@ -3,10 +3,9 @@ import datetime  import json  import jinja2 -from markupsafe import Markup - -from babel.numbers import format_decimal  from babel.dates import format_datetime +from babel.numbers import format_decimal +from markupsafe import Markup  @jinja2.pass_context diff --git a/fietsboek/models/__init__.py b/fietsboek/models/__init__.py index 828b689..2788407 100644 --- a/fietsboek/models/__init__.py +++ b/fietsboek/models/__init__.py @@ -3,18 +3,18 @@  Note that all SQLAlchemy models are re-imported here. You should only need to  access the submodules if you need some of the auxiliary definitions.  """ -from sqlalchemy import engine_from_config -from sqlalchemy.orm import sessionmaker -from sqlalchemy.orm import configure_mappers  import zope.sqlalchemy +from sqlalchemy import engine_from_config +from sqlalchemy.orm import configure_mappers, sessionmaker -# Import or define all models here to ensure they are attached to the -# ``Base.metadata`` prior to any initialization routines. -from .user import User, FriendRequest, Token  # flake8: noqa  from .badge import Badge  # flake8: noqa -from .track import Tag, Track, TrackCache, Upload  # flake8: noqa  from .comment import Comment  # flake8: noqa  from .image import ImageMetadata  # flake8: noqa +from .track import Tag, Track, TrackCache, Upload  # flake8: noqa + +# Import or define all models here to ensure they are attached to the +# ``Base.metadata`` prior to any initialization routines. +from .user import FriendRequest, Token, User  # flake8: noqa  # Run ``configure_mappers`` after defining all of the models to ensure  # all relationships can be setup. diff --git a/fietsboek/models/badge.py b/fietsboek/models/badge.py index f16e9bf..564e0d3 100644 --- a/fietsboek/models/badge.py +++ b/fietsboek/models/badge.py @@ -1,14 +1,7 @@  """The Badge model.""" -from sqlalchemy import ( -    Column, -    Integer, -    Text, -    LargeBinary, -    select, -) -from sqlalchemy.orm import relationship -  from pyramid.httpexceptions import HTTPNotFound +from sqlalchemy import Column, Integer, LargeBinary, Text, select +from sqlalchemy.orm import relationship  from .meta import Base diff --git a/fietsboek/models/comment.py b/fietsboek/models/comment.py index 386dfce..25293d2 100644 --- a/fietsboek/models/comment.py +++ b/fietsboek/models/comment.py @@ -1,11 +1,5 @@  """Comment model.""" -from sqlalchemy import ( -    Column, -    Integer, -    ForeignKey, -    Text, -    DateTime, -) +from sqlalchemy import Column, DateTime, ForeignKey, Integer, Text  from sqlalchemy.orm import relationship  from .meta import Base diff --git a/fietsboek/models/image.py b/fietsboek/models/image.py index cf507ec..1da8aa2 100644 --- a/fietsboek/models/image.py +++ b/fietsboek/models/image.py @@ -3,14 +3,7 @@  The actual image data is saved on disk, we only store the metadata such as an  image description here.  """ -from sqlalchemy import ( -    Column, -    Integer, -    ForeignKey, -    Text, -    UniqueConstraint, -    select, -) +from sqlalchemy import Column, ForeignKey, Integer, Text, UniqueConstraint, select  from sqlalchemy.orm import relationship  from .meta import Base diff --git a/fietsboek/models/track.py b/fietsboek/models/track.py index 93e37e7..9f9d7f6 100644 --- a/fietsboek/models/track.py +++ b/fietsboek/models/track.py @@ -11,44 +11,42 @@ keeps the user's metadata and the computed information separate, and allows for  example all cached data to be re-computed without interfering with the other  meta information.  """ +import datetime  import enum  import gzip -import datetime  import logging -from typing import Optional, List, Set, TYPE_CHECKING, Union -  from itertools import chain +from typing import TYPE_CHECKING, List, Optional, Set, Union +from babel.numbers import format_decimal +from markupsafe import Markup +from pyramid.authorization import ( +    ALL_PERMISSIONS, +    ACLAllowed, +    ACLHelper, +    Allow, +    Authenticated, +    Everyone, +) +from pyramid.httpexceptions import HTTPNotFound +from pyramid.i18n import Localizer +from pyramid.i18n import TranslationString as _  from sqlalchemy import (      Column, -    Integer, -    Text, -    LargeBinary,      DateTime, -    ForeignKey, -    Float,      Enum, +    Float, +    ForeignKey, +    Integer, +    LargeBinary,      Table, +    Text,      select,  )  from sqlalchemy.orm import relationship -from pyramid.httpexceptions import HTTPNotFound -from pyramid.i18n import TranslationString as _, Localizer -from pyramid.authorization import ( -    Allow, -    Everyone, -    Authenticated, -    ALL_PERMISSIONS, -    ACLHelper, -    ACLAllowed, -) - -from markupsafe import Markup -from babel.numbers import format_decimal - -from .meta import Base  from .. import util +from .meta import Base  if TYPE_CHECKING:      from .. import models diff --git a/fietsboek/models/user.py b/fietsboek/models/user.py index 0fe7877..62c935e 100644 --- a/fietsboek/models/user.py +++ b/fietsboek/models/user.py @@ -1,30 +1,32 @@  """User models for fietsboek."""  import datetime  import enum -import uuid  import secrets +import uuid  from functools import reduce +from cryptography.exceptions import InvalidKey +from cryptography.hazmat.primitives.kdf.scrypt import Scrypt  from sqlalchemy import ( +    Boolean,      Column, +    DateTime, +    Enum, +    ForeignKey,      Index,      Integer, -    Text,      LargeBinary, -    Boolean,      Table, -    ForeignKey, +    Text,      UniqueConstraint, -    DateTime, -    Enum, +    delete, +    func, +    select, +    union,  )  from sqlalchemy.orm import relationship, with_parent -from sqlalchemy.orm.session import object_session  from sqlalchemy.orm.attributes import flag_dirty -from sqlalchemy import select, union, delete, func - -from cryptography.hazmat.primitives.kdf.scrypt import Scrypt -from cryptography.exceptions import InvalidKey +from sqlalchemy.orm.session import object_session  from .meta import Base diff --git a/fietsboek/scripts/fietsctl.py b/fietsboek/scripts/fietsctl.py index 75c615a..b5e1036 100644 --- a/fietsboek/scripts/fietsctl.py +++ b/fietsboek/scripts/fietsctl.py @@ -7,8 +7,7 @@ import sys  from pyramid.paster import bootstrap, setup_logging  from sqlalchemy import select -from .. import models, __VERSION__ - +from .. import __VERSION__, models  EXIT_OKAY = 0  EXIT_FAILURE = 1 diff --git a/fietsboek/security.py b/fietsboek/security.py index 6fbc5db..1dd2390 100644 --- a/fietsboek/security.py +++ b/fietsboek/security.py @@ -1,16 +1,14 @@  """Module implementing the user authentication.""" +from pyramid.authentication import AuthTktCookieHelper, SessionAuthenticationHelper +from pyramid.authorization import ACLHelper, Authenticated, Everyone +from pyramid.interfaces import ISecurityPolicy  from pyramid.security import Allowed, Denied -from pyramid.authentication import SessionAuthenticationHelper, AuthTktCookieHelper -from pyramid.authorization import ACLHelper, Everyone, Authenticated  from pyramid.traversal import DefaultRootFactory -from pyramid.interfaces import ISecurityPolicy -from zope.interface import implementer -  from sqlalchemy import select +from zope.interface import implementer  from . import models -  ADMIN_PERMISSIONS = {"admin"} diff --git a/fietsboek/summaries.py b/fietsboek/summaries.py index fcbbc86..670c8f2 100644 --- a/fietsboek/summaries.py +++ b/fietsboek/summaries.py @@ -1,5 +1,5 @@  """Module for a yearly/monthly track summary.""" -from typing import List, Dict +from typing import Dict, List  from fietsboek.models.track import TrackWithMetadata diff --git a/fietsboek/updater/__init__.py b/fietsboek/updater/__init__.py index b136a6c..d1532b4 100644 --- a/fietsboek/updater/__init__.py +++ b/fietsboek/updater/__init__.py @@ -1,21 +1,21 @@  """Updating (data migration) logic for fietsboek.""" -import logging  import datetime +import importlib.util +import logging  import random  import string -import importlib.util  from pathlib import Path  from typing import List +import alembic.command +import alembic.config +import alembic.runtime +  # Compat for Python < 3.9  import importlib_resources +import jinja2  import pyramid.paster -import alembic.runtime -import alembic.config -import alembic.command  import sqlalchemy -import jinja2 -  LOGGER = logging.getLogger(__name__) diff --git a/fietsboek/updater/cli.py b/fietsboek/updater/cli.py index d19e444..d1b9a3e 100644 --- a/fietsboek/updater/cli.py +++ b/fietsboek/updater/cli.py @@ -7,11 +7,11 @@ takes care of running the database migrations, migrating the data directory and  migrating the configuration.  """  import logging.config +  import click  from . import Updater -  # We keep this as a separate option that is added to each subcommand as Click  # (unlike argparse) cannot handle "--help" without the required arguments of  # the parent (so "fietsupdate update --help" would error out) diff --git a/fietsboek/updater/scripts/upd_30ppwg8zi4ujb46f.py b/fietsboek/updater/scripts/upd_30ppwg8zi4ujb46f.py index 983ea45..31ee9a0 100644 --- a/fietsboek/updater/scripts/upd_30ppwg8zi4ujb46f.py +++ b/fietsboek/updater/scripts/upd_30ppwg8zi4ujb46f.py @@ -5,15 +5,16 @@ directory instead.  Date created: 2022-12-14 22:33:32.837737  """ -from fietsboek.updater.script import UpdateScript - -import shutil  import gzip -import brotli +import shutil  from pathlib import Path + +import brotli  from sqlalchemy import create_engine  from sqlalchemy.sql import text +from fietsboek.updater.script import UpdateScript +  update_id = '30ppwg8zi4ujb46f'  previous = [      'v0.4.0', diff --git a/fietsboek/util.py b/fietsboek/util.py index 789fc3b..8dd81c0 100644 --- a/fietsboek/util.py +++ b/fietsboek/util.py @@ -1,27 +1,26 @@  """Various utility functions."""  import datetime -import re  import os -import unicodedata +import re  import secrets -from typing import Optional, List, Union +import unicodedata +from typing import List, Optional, Union -# Compat for Python < 3.9 -import importlib_resources  import babel -import markdown  import bleach  import gpxpy -import webob -import sqlalchemy -from pyramid.i18n import TranslationString as _ +# Compat for Python < 3.9 +import importlib_resources +import markdown +import sqlalchemy +import webob +from markupsafe import Markup  from pyramid.httpexceptions import HTTPBadRequest +from pyramid.i18n import TranslationString as _  from pyramid.request import Request -from markupsafe import Markup  from sqlalchemy import select -  ALLOWED_TAGS = (      bleach.sanitizer.ALLOWED_TAGS      + diff --git a/fietsboek/views/account.py b/fietsboek/views/account.py index b181148..39a62e5 100644 --- a/fietsboek/views/account.py +++ b/fietsboek/views/account.py @@ -1,9 +1,9 @@  """Account related endpoints.""" -from pyramid.view import view_config -from pyramid.i18n import TranslationString as _  from pyramid.httpexceptions import HTTPForbidden, HTTPFound +from pyramid.i18n import TranslationString as _ +from pyramid.view import view_config -from .. import models, util, email +from .. import email, models, util  from ..models.user import TokenType diff --git a/fietsboek/views/admin.py b/fietsboek/views/admin.py index 454d1e1..2c489a7 100644 --- a/fietsboek/views/admin.py +++ b/fietsboek/views/admin.py @@ -1,8 +1,7 @@  """Admin views.""" -from pyramid.view import view_config  from pyramid.httpexceptions import HTTPFound  from pyramid.i18n import TranslationString as _ - +from pyramid.view import view_config  from sqlalchemy import select  from .. import models diff --git a/fietsboek/views/browse.py b/fietsboek/views/browse.py index 377e073..ede6b21 100644 --- a/fietsboek/views/browse.py +++ b/fietsboek/views/browse.py @@ -2,13 +2,12 @@  import datetime  from io import RawIOBase  from typing import List -from zipfile import ZipFile, ZIP_DEFLATED +from zipfile import ZIP_DEFLATED, ZipFile -from pyramid.view import view_config -from pyramid.httpexceptions import HTTPForbidden, HTTPNotFound, HTTPBadRequest +from pyramid.httpexceptions import HTTPBadRequest, HTTPForbidden, HTTPNotFound  from pyramid.response import Response - -from sqlalchemy import select, func, or_ +from pyramid.view import view_config +from sqlalchemy import func, or_, select  from sqlalchemy.orm import aliased  from .. import models, util diff --git a/fietsboek/views/default.py b/fietsboek/views/default.py index 8d0ad7e..1c30524 100644 --- a/fietsboek/views/default.py +++ b/fietsboek/views/default.py @@ -1,20 +1,18 @@  """Home views.""" -from pyramid.view import view_config +from markupsafe import Markup  from pyramid.httpexceptions import HTTPFound, HTTPNotFound -from pyramid.security import remember, forget  from pyramid.i18n import TranslationString as _  from pyramid.interfaces import ISecurityPolicy  from pyramid.renderers import render_to_response - +from pyramid.security import forget, remember +from pyramid.view import view_config  from sqlalchemy import select -from sqlalchemy.orm import aliased  from sqlalchemy.exc import NoResultFound +from sqlalchemy.orm import aliased -from markupsafe import Markup - -from .. import models, summaries, util, email -from ..models.user import PasswordMismatch, TokenType +from .. import email, models, summaries, util  from ..models.track import TrackType, TrackWithMetadata +from ..models.user import PasswordMismatch, TokenType  @view_config(route_name="home", renderer="fietsboek:templates/home.jinja2") diff --git a/fietsboek/views/detail.py b/fietsboek/views/detail.py index a6d845a..6f8ed44 100644 --- a/fietsboek/views/detail.py +++ b/fietsboek/views/detail.py @@ -1,24 +1,22 @@  """Track detail views."""  import datetime -import logging  import gzip +import logging -from pyramid.view import view_config -from pyramid.response import Response, FileResponse -from pyramid.i18n import TranslationString as _  from pyramid.httpexceptions import (      HTTPFound, -    HTTPNotFound, -    HTTPNotAcceptable,      HTTPInternalServerError, +    HTTPNotAcceptable, +    HTTPNotFound,  ) - +from pyramid.i18n import TranslationString as _ +from pyramid.response import FileResponse, Response +from pyramid.view import view_config  from sqlalchemy import select  from .. import models, util  from ..models.track import TrackWithMetadata -  LOGGER = logging.getLogger(__name__) diff --git a/fietsboek/views/edit.py b/fietsboek/views/edit.py index e6a6796..e3fe99d 100644 --- a/fietsboek/views/edit.py +++ b/fietsboek/views/edit.py @@ -1,17 +1,15 @@  """Views for editing a track.""" -import logging  import datetime +import logging  from collections import namedtuple +from pyramid.httpexceptions import HTTPBadRequest, HTTPFound  from pyramid.view import view_config -from pyramid.httpexceptions import HTTPFound, HTTPBadRequest -  from sqlalchemy import select -from .. import models, util, actions +from .. import actions, models, util  from ..data import TrackDataDir -from ..models.track import Visibility, TrackType - +from ..models.track import TrackType, Visibility  ImageEmbed = namedtuple("ImageEmbed", "name url description") diff --git a/fietsboek/views/profile.py b/fietsboek/views/profile.py index 7a929aa..6354465 100644 --- a/fietsboek/views/profile.py +++ b/fietsboek/views/profile.py @@ -1,10 +1,9 @@  """Views corresponding to the user profile."""  import datetime -from pyramid.view import view_config +from pyramid.httpexceptions import HTTPForbidden, HTTPFound, HTTPNotFound  from pyramid.i18n import TranslationString as _ -from pyramid.httpexceptions import HTTPFound, HTTPNotFound, HTTPForbidden - +from pyramid.view import view_config  from sqlalchemy import select  from .. import models, util diff --git a/fietsboek/views/tileproxy.py b/fietsboek/views/tileproxy.py index 1ec609b..e53c32b 100644 --- a/fietsboek/views/tileproxy.py +++ b/fietsboek/views/tileproxy.py @@ -7,22 +7,20 @@ access control for services like thunderforest.com.  Additionally, this protects the users' IP, as only fietsboek can see it.  """  import datetime -import random  import logging -from typing import List +import random  from itertools import chain +from typing import List -from pyramid.view import view_config +import requests +from pyramid.httpexceptions import HTTPBadRequest, HTTPGatewayTimeout  from pyramid.request import Request  from pyramid.response import Response -from pyramid.httpexceptions import HTTPBadRequest, HTTPGatewayTimeout - -import requests +from pyramid.view import view_config  from requests.exceptions import ReadTimeout  from .. import __VERSION__ -from ..config import Config, LayerType, LayerAccess, TileLayerConfig - +from ..config import Config, LayerAccess, LayerType, TileLayerConfig  LOGGER = logging.getLogger(__name__) diff --git a/fietsboek/views/upload.py b/fietsboek/views/upload.py index 98aad3b..49c839c 100644 --- a/fietsboek/views/upload.py +++ b/fietsboek/views/upload.py @@ -2,18 +2,15 @@  import datetime  import logging -from pyramid.httpexceptions import HTTPFound, HTTPBadRequest +import gpxpy +from pyramid.httpexceptions import HTTPBadRequest, HTTPFound +from pyramid.i18n import TranslationString as _  from pyramid.response import Response  from pyramid.view import view_config -from pyramid.i18n import TranslationString as _ -  from sqlalchemy import select -import gpxpy - -from .. import models, util, actions -from ..models.track import Visibility, TrackType - +from .. import actions, models, util +from ..models.track import TrackType, Visibility  LOGGER = logging.getLogger(__name__) diff --git a/pyproject.toml b/pyproject.toml index 4e81701..292351a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -99,3 +99,8 @@ main = "fietsboek:main"  [tool.black]  line-length = 100  extend-exclude = '''upd_.+\.py|^/fietsboek/alembic/versions/.+''' + +[tool.isort] +profile = "black" +line_length = 99 +known_local_folder = ["fietsboek"] @@ -62,3 +62,9 @@ deps = black  commands_pre =  commands =      black --diff --check fietsboek + +[testenv:isort] +deps = isort +commands_pre = +commands = +    isort --check --diff fietsboek  | 
