diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 69d9ee918938fb6ac697ed042ee4ededb8fe8e44..28d44d4589b4f9b1a434e06bb5b22f5e2626b32a 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,32 +1,38 @@
 # See https://pre-commit.com for more information
 # See https://pre-commit.com/hooks.html for more hooks
 repos:
-  - repo: https://github.com/timothycrosley/isort
-    rev: 5.10.1
-    hooks:
-      - id: isort
-        args: [--settings-path, "pyproject.toml"]
   - repo: https://github.com/psf/black
-    rev: 22.3.0
+    rev: 22.10.0
     hooks:
       - id: black
-        exclude: bob/devtools/templates/setup.py
+  - repo: https://github.com/pycqa/docformatter
+    rev: "v1.5.0"
+    hooks:
+      - id: docformatter
+  - repo: https://github.com/pycqa/isort
+    rev: "5.10.1"
+    hooks:
+      - id: isort
   - repo: https://gitlab.com/pycqa/flake8
-    rev: 4.0.1
+    rev: "3.9.2"
     hooks:
       - id: flake8
-        exclude: bob/ip/binseg/configs
+  - repo: https://github.com/pre-commit/mirrors-mypy
+    rev: "v0.982"
+    hooks:
+    - id: mypy
+      args: [--no-strict-optional, --ignore-missing-imports]
+      exclude: '^.*/data/second_config\.py$'
   - repo: https://github.com/pre-commit/pre-commit-hooks
-    rev: v4.1.0
+    rev: "v4.3.0"
     hooks:
       - id: check-ast
-        exclude: bob/devtools/templates/setup.py
+      - id: check-added-large-files
+      - id: check-toml
+      - id: check-yaml
+        exclude: conda/meta.yaml
+      - id: debug-statements
       - id: check-case-conflict
       - id: trailing-whitespace
       - id: end-of-file-fixer
       - id: debug-statements
-        exclude: bob/devtools/templates/setup.py
-      - id: check-added-large-files
-        exclude: bob/devtools/templates/setup.py
-      - id: check-yaml
-        exclude: .*/meta.*.yaml
diff --git a/doc/example_alias.py b/doc/example_alias.py
index 997719df57bd35bd1868f3a741babd3cb4d40729..9c67734510b87e694e27cf97a263dc5222e23b3e 100644
--- a/doc/example_alias.py
+++ b/doc/example_alias.py
@@ -1,5 +1,4 @@
-"""An example script to demonstrate config-file option readout
-"""
+"""An example script to demonstrate config-file option readout."""
 
 # To improve loading performance, we recommend you only import the very
 # essential packages needed to start the CLI.  Defer all other imports to
diff --git a/doc/example_cli.py b/doc/example_cli.py
index 55c80952b4d88b06a744d35679deaec13b3d604b..bd53e1c7d2ac92b47a4fefa052e83b59dff6e486 100644
--- a/doc/example_cli.py
+++ b/doc/example_cli.py
@@ -1,5 +1,4 @@
-"""An example script to demonstrate config-file option readout
-"""
+"""An example script to demonstrate config-file option readout."""
 
 # To improve loading performance, we recommend you only import the very
 # essential packages needed to start the CLI.  Defer all other imports to
@@ -40,7 +39,7 @@ Examples:
 @click.version_option(package_name="exposed")
 @click.pass_context
 def main(ctx, **_):
-    """Tests our Click interfaces"""
+    """Tests our Click interfaces."""
 
     # Add imports needed for your code here, and avoid spending time loading!
 
diff --git a/doc/example_config.py b/doc/example_config.py
index 32c47368bd4b369eee15e2bca98a55c11db639c5..416883bf910fcd47b0de984ffd632d673a72c846 100644
--- a/doc/example_config.py
+++ b/doc/example_config.py
@@ -6,7 +6,7 @@ logger = setup(__name__.split(".", 1)[0])
 
 @config_group(logger=logger, entry_point_group="exposed.test.config")
 def main(**kwargs):
-    """Use this command to list/describe/copy package config resources"""
+    """Use this command to list/describe/copy package config resources."""
     pass
 
 
diff --git a/src/exposed/click.py b/src/exposed/click.py
index c66c04a189ef50872c1ddbcaff4acf90bb76fb62..a1613dd40b0ab6cbd805b190ac74d48c782fde14 100644
--- a/src/exposed/click.py
+++ b/src/exposed/click.py
@@ -34,7 +34,7 @@ def verbosity_option(
     dflt: int = 0,
     **kwargs: typing.Any,
 ) -> typing.Callable[..., typing.Any]:
-    """Click-option decorator that adds a ``-v``/``--verbose`` option to a cli
+    """Click-option decorator that adds a ``-v``/``--verbose`` option to a cli.
 
     This decorator adds a click option to your CLI to set the log-level on a
     provided :py:class:`logging.Logger`.  You must specifically determine the
@@ -76,7 +76,6 @@ def verbosity_option(
 
         A callable, that follows the :py:mod:`click`-framework policy for
         option decorators.  Use it accordingly.
-
     """
 
     def custom_verbosity_option(f):
@@ -118,7 +117,7 @@ def verbosity_option(
 
 
 class ConfigCommand(click.Command):
-    """A :py:class:`click.Command` that can read options from config files
+    """A :py:class:`click.Command` that can read options from config files.
 
     .. warning::
 
@@ -138,7 +137,6 @@ class ConfigCommand(click.Command):
             entry-points will be searched
 
         **kwargs: Named parameters passed to :py:class:`click.Command`
-
     """
 
     config_argument_name: str
@@ -202,7 +200,7 @@ will override the values of configuration files. You can run this command with
         param: typing.Any,
         value: typing.TextIO | None,
     ) -> None:
-        """Generate configuration file from parameters and context
+        """Generate configuration file from parameters and context.
 
         Using this function will conclude the command-line execution.
 
@@ -210,7 +208,6 @@ will override the values of configuration files. You can run this command with
         Arguments:
 
             ctx: Click context
-
         """
 
         config_file = value
@@ -221,7 +218,7 @@ will override the values of configuration files. You can run this command with
         config_file.write('"""')
         config_file.write(
             f"Configuration file automatically generated at "
-            f"{time.strftime('%d/%m/%Y')}\n{ctx.command_path}\n"
+            f"{time.strftime('%d/%m/%Y')}.\n\n{ctx.command_path}\n"
         )
 
         if self.help:
@@ -231,7 +228,7 @@ will override the values of configuration files. You can run this command with
         if self.epilog:
             config_file.write("\n\n{}".format(self.epilog.replace("\b\n", "")))
 
-        config_file.write('"""\n')
+        config_file.write('\n"""\n')
 
         for param in self.params:
             if not isinstance(param, ResourceOption):
@@ -277,7 +274,7 @@ will override the values of configuration files. You can run this command with
 
 class CustomParamType(click.ParamType):
     """Custom parameter class allowing click to receive complex Python types as
-    parameters"""
+    parameters."""
 
     name = "custom"
 
@@ -313,7 +310,6 @@ class ResourceOption(click.Option):
 
 
     Attributes:
-
     """
 
     entry_point_group: str | None
@@ -392,7 +388,7 @@ class ResourceOption(click.Option):
     def consume_value(
         self, ctx: click.Context, opts: dict
     ) -> tuple[typing.Any, ParameterSource]:
-        """Retrieves value for parameter from appropriate context
+        """Retrieves value for parameter from appropriate context.
 
         This method will retrive the value of its own parameter from the
         appropriate context, by trying various sources.
@@ -409,7 +405,6 @@ class ResourceOption(click.Option):
 
             A tuple containing the parameter value (of any type) and the source
             it used to retrieve it.
-
         """
 
         if (
@@ -451,7 +446,7 @@ class ResourceOption(click.Option):
     def type_cast_value(
         self, ctx: click.Context, value: typing.Any
     ) -> typing.Any:
-        """Convert and validate a value against the option's type
+        """Convert and validate a value against the option's type.
 
         This method considers the option's ``type``, ``multiple``, and ``nargs``.
         Furthermore, if the an ``entry_point_group`` is provided, it will load
@@ -467,7 +462,6 @@ class ResourceOption(click.Option):
         Returns:
 
             The cast value
-
         """
         value = super().type_cast_value(ctx, value)
 
@@ -486,7 +480,7 @@ class ResourceOption(click.Option):
 
 
 class AliasedGroup(click.Group):
-    """Class that handles prefix aliasing for commands
+    """Class that handles prefix aliasing for commands.
 
     Basically just implements get_command that is used by click to choose the
     command based on the name.
@@ -498,7 +492,7 @@ class AliasedGroup(click.Group):
     """
 
     def get_command(self, ctx, cmd_name):
-        """get_command with prefix aliasing"""
+        """get_command with prefix aliasing."""
         rv = click.Group.get_command(self, ctx, cmd_name)
         if rv is not None:
             return rv
@@ -514,7 +508,7 @@ def user_defaults_group(
     logger: logging.Logger,
     config: UserDefaults,
 ) -> typing.Callable[..., typing.Any]:
-    """Decorator to add a command group to read/write RC configuration
+    """Decorator to add a command group to read/write RC configuration.
 
     This decorator adds a whole command group to a user predefined function
     which is part of the user's CLI.  The command group allows the user to get
@@ -543,7 +537,6 @@ def user_defaults_group(
 
        $ user-cli rc --help
        usage: ...
-
     """
 
     def group_decorator(
@@ -562,7 +555,7 @@ def user_defaults_group(
         @group_wrapper.command(context_settings=_COMMON_CONTEXT_SETTINGS)
         @verbosity_option(logger=logger)
         def show(**_: typing.Any) -> None:
-            """Shows the user-defaults file contents"""
+            """Shows the user-defaults file contents."""
             click.echo(str(config).strip())
 
         @group_wrapper.command(
@@ -573,9 +566,9 @@ def user_defaults_group(
         def get(key: str, **_: typing.Any) -> None:
             """Prints a key from the user-defaults file.
 
-            Retrieves the value of the requested KEY and displays it.  The KEY
-            may contain dots (``.``) to access values from subsections in the
-            TOML_ document.
+            Retrieves the value of the requested KEY and displays it.
+            The KEY may contain dots (``.``) to access values from
+            subsections in the TOML_ document.
             """
 
             try:
@@ -603,7 +596,6 @@ def user_defaults_group(
                This command will override the current configuration file and my
                erase any user comments added by hand.  To avoid this, simply
                edit your configuration file by hand.
-
             """
             try:
                 tmp = tomli.loads(f"v = {value}")
@@ -629,7 +621,7 @@ def user_defaults_group(
         @click.argument("key")
         @verbosity_option(logger=logger)
         def rm(key: str, **_: typing.Any) -> None:
-            """Removes the given key from the configuration file
+            """Removes the given key from the configuration file.
 
             This command will remove the KEY from the configuration file.  If
             the input key corresponds to a section in the configuration file,
@@ -640,7 +632,6 @@ def user_defaults_group(
                This command will override the current configuration file and my
                erase any user comments added by hand.  To avoid this, simply
                edit your configuration file by hand.
-
             """
             try:
                 del config[key]
@@ -663,7 +654,8 @@ def config_group(
     logger: logging.Logger,
     entry_point_group: str,
 ) -> typing.Callable[..., typing.Any]:
-    """Decorator to add a command group to list/describe/copy job configurations
+    """Decorator to add a command group to list/describe/copy job
+    configurations.
 
     This decorator adds a whole command group to a user predefined function
     which is part of the user's CLI.  The command group provdes an interface to
@@ -691,7 +683,6 @@ def config_group(
 
        $ user-cli config --help
        usage: ...
-
     """
 
     def group_decorator(
@@ -709,7 +700,7 @@ def config_group(
         @click.pass_context
         @verbosity_option(logger=logger)
         def list(ctx, **_: typing.Any):
-            """Lists installed configuration resources"""
+            """Lists installed configuration resources."""
 
             from .config import _retrieve_entry_points
 
@@ -718,21 +709,21 @@ def config_group(
             }
 
             # all modules with configuration resources
-            modules = set(
+            modules: set[str] = set(
                 # note: k.module does not exist on Python < 3.9
                 k.value.split(":")[0].rsplit(".", 1)[0]
                 for k in entry_points.values()
             )
-            keep_modules = []
+            keep_modules: set[str] = set()
             for k in sorted(modules):
                 if k not in keep_modules and not any(
                     k.startswith(to_keep) for to_keep in keep_modules
                 ):
-                    keep_modules.append(k)
+                    keep_modules.add(k)
             modules = keep_modules
 
             # sort data entries by originating module
-            entry_points_by_module = {}
+            entry_points_by_module: dict[str, dict[str, EntryPoint]] = {}
             for k in modules:
                 entry_points_by_module[k] = {}
                 for name, ep in entry_points.items():
@@ -809,7 +800,7 @@ def config_group(
         )
         @verbosity_option(logger=logger)
         def describe(ctx, name, **_: typing.Any):
-            """Describes a specific configuration resource"""
+            """Describes a specific configuration resource."""
 
             from .config import _retrieve_entry_points
 
@@ -856,7 +847,8 @@ def config_group(
         )
         @verbosity_option(logger=logger)
         def copy(source, destination, **_: typing.Any):
-            """Copies a specific configuration resource so it can be modified locally"""
+            """Copies a specific configuration resource so it can be modified
+            locally."""
 
             from .config import _retrieve_entry_points
 
diff --git a/src/exposed/config.py b/src/exposed/config.py
index 9e5c74af688e248158406c8578b2eacb1c1465a3..2507e614c93e8955e7b74ecb15ad8386e7b43c90 100644
--- a/src/exposed/config.py
+++ b/src/exposed/config.py
@@ -1,7 +1,6 @@
 # vim: set fileencoding=utf-8 :
 
-"""Functionality to implement python-based config file parsing and loading.
-"""
+"""Functionality to implement python-based config file parsing and loading."""
 
 from __future__ import annotations
 
@@ -13,6 +12,7 @@ import sys
 import types
 import typing
 
+from importlib.abc import FileLoader
 from importlib.metadata import EntryPoint, entry_points
 
 logger = logging.getLogger(__name__)
@@ -24,7 +24,7 @@ to avoid the garbage collector to collect some already imported modules.
 
 
 def _load_context(path: str, mod: types.ModuleType) -> types.ModuleType:
-    """Loads the Python file as module, returns a resolved context
+    """Loads the Python file as module, returns a resolved context.
 
     This function is implemented in a way that is both Python 2 and Python 3
     compatible. It does not directly load the python file, but reads its
@@ -51,7 +51,6 @@ def _load_context(path: str, mod: types.ModuleType) -> types.ModuleType:
     Returns:
 
         A python module with the fully resolved context
-
     """
 
     # executes the module code on the context of previously imported modules
@@ -77,18 +76,15 @@ def _get_module_filename(module_name: str) -> str | None:
     Returns:
 
         The path that corresponds to file implementing the provided module name
-
     """
 
     try:
         loader = pkgutil.get_loader(module_name)
-        if loader is None:
-            return None
-        return loader.path
-    except ImportError:
+        if isinstance(loader, FileLoader):
+            return str(loader.path)
+        return None
+    except (ImportError,):
         return None
-    except AttributeError:
-        return loader.filename
 
 
 def _object_name(
@@ -103,7 +99,7 @@ def _object_name(
 
 
 def _retrieve_entry_points(group: str) -> typing.Iterable[EntryPoint]:
-    """Wraps various entry-point retrieval mechanisms
+    """Wraps various entry-point retrieval mechanisms.
 
     For Python 3.9 and 3.10, :py:func:`importlib.metadata.entry_points()`
     returns a dictionary keyed by entry-point group names.  From Python 3.10
@@ -127,7 +123,8 @@ def _resolve_entry_point_or_modules(
     entry_point_group: str | None = None,
     common_name: str | None = None,
 ) -> tuple[list[str], list[str], list[str]]:
-    """Resolves a mixture of paths, entry point names, and module names to path.
+    """Resolves a mixture of paths, entry point names, and module names to
+    path.
 
     This function can resolve actual file system paths, ``setup.py``
     entry-point names and module names to a set of file system paths.
@@ -164,7 +161,6 @@ def _resolve_entry_point_or_modules(
 
         ValueError: If one of the paths cannot be resolved to an actual path to
             a file.
-
     """
 
     if entry_point_group is not None:
@@ -226,7 +222,7 @@ def load(
     entry_point_group: str | None = None,
     attribute_name: str | None = None,
 ) -> typing.Union[types.ModuleType, typing.Any]:
-    """Loads a set of configuration files, in sequence
+    """Loads a set of configuration files, in sequence.
 
     This method will load one or more configuration files. Every time a
     configuration file is loaded, the context (variables) loaded from the
@@ -269,7 +265,6 @@ def load(
 
         ValueError: If attribute_name is given but entry_point_group is not
             given.
-
     """
 
     # resolve entry points to paths
@@ -334,7 +329,6 @@ def mod_to_context(mod: types.ModuleType) -> dict[str, typing.Any]:
 
         The context that was in ``mod``, as a dictionary mapping strings to
         objects.
-
     """
     return {
         k: v
@@ -345,10 +339,11 @@ def mod_to_context(mod: types.ModuleType) -> dict[str, typing.Any]:
 
 def resource_keys(
     entry_point_group: str,
-    exclude_packages: tuple[str] = tuple(),
-    strip: tuple[str] = ("dummy",),
+    exclude_packages: tuple[str, ...] = tuple(),
+    strip: tuple[str, ...] = ("dummy",),
 ) -> list[str]:
-    """Reads and returns all resources that are registered on a entry-point group.
+    """Reads and returns all resources that are registered on a entry-point
+    group.
 
     Entry points from the given ``exclude_packages`` list are ignored.  Notice
     we are using :py:mod:`importlib.metadata` to load entry-points, and that
@@ -371,7 +366,6 @@ def resource_keys(
     Returns:
 
         Alphabetically sorted list of resources matching your query
-
     """
 
     ret_list = [
diff --git a/src/exposed/logging.py b/src/exposed/logging.py
index 227b5723247a357592f7549e4eb3f58c82d9c4f2..cdabd768cfdea39d4ebebcce6c80a8a42b3e6bf5 100644
--- a/src/exposed/logging.py
+++ b/src/exposed/logging.py
@@ -24,7 +24,7 @@ def setup(
     low_level_stream: typing.TextIO = sys.stdout,
     high_level_stream: typing.TextIO = sys.stderr,
 ) -> logging.Logger:
-    """This function returns a logger object that is ready for console logging
+    """This function returns a logger object that is ready for console logging.
 
     Retrieves (as with :py:func:`logging.getLogger()`) the given logger, and
     then attaches 2 handlers (defined on the module) to it:
@@ -61,7 +61,6 @@ def setup(
 
         The configured logger. The same logger can be retrieved using the
         :py:func:`logging.getLogger` function.
-
     """
 
     logger = logging.getLogger(logger_name)
diff --git a/src/exposed/rc.py b/src/exposed/rc.py
index 9674a6434042513e67e7fe5339597e9d9567e6d4..8fd2e7e785fcf6edd72e2a8e35ba84d7bd2852d2 100644
--- a/src/exposed/rc.py
+++ b/src/exposed/rc.py
@@ -49,7 +49,6 @@ class UserDefaults(collections.abc.MutableMapping):
     Attributes:
 
         path: The current path to the user defaults base file.
-
     """
 
     def __init__(
@@ -78,7 +77,7 @@ class UserDefaults(collections.abc.MutableMapping):
         self.read()
 
     def read(self) -> None:
-        """Reads configuration file, replaces any internal values"""
+        """Reads configuration file, replaces any internal values."""
 
         if self.path.exists():
             self.logger.debug(
@@ -112,7 +111,7 @@ class UserDefaults(collections.abc.MutableMapping):
             self.logger.debug("Initializing empty user configuration...")
 
     def write(self) -> None:
-        """Stores any modifications done on the user configuration"""
+        """Stores any modifications done on the user configuration."""
 
         if self.path.exists():
             backup = pathlib.Path(str(self.path) + "~")
diff --git a/tests/conftest.py b/tests/conftest.py
index 72e993e08032b387d6eb766b9e00fc1ff2b290de..5144e0921ff7e437bf0d685341bfa3930bd2b293 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -73,7 +73,7 @@ class MyCliRunner(CliRunner):
 
 @pytest.fixture
 def cli_runner(request) -> MyCliRunner:
-    """A wrapper round Click's test CliRunner to improve usefulness"""
+    """A wrapper round Click's test CliRunner to improve usefulness."""
 
     return MyCliRunner(
         # workaround Click's environment isolation so debugging works.
@@ -83,6 +83,6 @@ def cli_runner(request) -> MyCliRunner:
 
 @fixture
 def datadir(request) -> pathlib.Path:
-    """Returns the directory in which the test is sitting"""
+    """Returns the directory in which the test is sitting."""
 
     return pathlib.Path(request.module.__file__).parents[0] / "data"
diff --git a/tests/data/basic_config.py b/tests/data/basic_config.py
index 920c3060852dbbe6e77c88d92337227751479896..0a6d67b5083a9eceb6ec768d9f7e15f18a3b362f 100644
--- a/tests/data/basic_config.py
+++ b/tests/data/basic_config.py
@@ -1,4 +1,4 @@
-"""Example configuration module"""
+"""Example configuration module."""
 
 a = 1
 b = a + 2
diff --git a/tests/data/test_dump_config.py b/tests/data/test_dump_config.py
index 8270c8d98b3c68fc5475410a4ffbfb7a9029b558..a4ce209e84e7fa8d37afc62aaeb657283919d6c3 100644
--- a/tests/data/test_dump_config.py
+++ b/tests/data/test_dump_config.py
@@ -1,9 +1,11 @@
-"""Configuration file automatically generated at 09/09/2022
+"""Configuration file automatically generated at 09/09/2022.
+
 test
 
-Test command
+Test command.
 
-Examples!"""
+Examples!
+"""
 
 # test = /my/path/test.txt
 """Required parameter: test (-t, --test)
diff --git a/tests/data/test_dump_config2.py b/tests/data/test_dump_config2.py
index a0ed88231e41d00501e3b8f30383481482f620de..d6ea01e3f8badd84ccd0cf74a3de3b3bbd7a54fd 100644
--- a/tests/data/test_dump_config2.py
+++ b/tests/data/test_dump_config2.py
@@ -1,7 +1,8 @@
-"""Configuration file automatically generated at 10/09/2022
+"""Configuration file automatically generated at 10/09/2022.
+
 test
 
-Blablabla bli blo
+Blablabla bli blo.
 
         Parameters
         ----------
@@ -10,7 +11,8 @@ Blablabla bli blo
         yyy : callable
             bli bla blo bla bla bla
 
-        [CONFIG]...           BLA BLA BLA BLA"""
+        [CONFIG]...           BLA BLA BLA BLA
+"""
 
 # database = None
 """Required parameter: database (--database, -d)
diff --git a/tests/test_click.py b/tests/test_click.py
index e43d219f02e2565364a8ed425951420574ee1f88..260e7ad48e895c54f81a03807bd7badb60de9f4f 100644
--- a/tests/test_click.py
+++ b/tests/test_click.py
@@ -54,7 +54,6 @@ def test_commands_with_config_1():
 
 
 def test_commands_with_config_2():
-
     # test option with valid default value
     @click.command(cls=ConfigCommand, entry_point_group="exposed.test.config")
     @click.option("-a", type=click.INT, cls=ResourceOption)
@@ -82,7 +81,6 @@ def test_commands_with_config_2():
 
 
 def test_commands_with_config_3():
-
     # test required options
     @click.command(cls=ConfigCommand, entry_point_group="exposed.test.config")
     @click.option("-a", cls=ResourceOption, required=True)
@@ -112,7 +110,6 @@ def test_commands_with_config_3():
 
 
 def _assert_config_dump(output, ref, ref_date):
-
     with output.open("rt") as f, open(ref, "rt") as f2:
         diff = difflib.ndiff(f.readlines(), f2.readlines())
         important_diffs = [k for k in diff if k.startswith(("+", "-"))]
@@ -150,7 +147,7 @@ def test_config_dump(tmp_path, datadir):
     )
     @verbosity_option(logging.getLogger(__name__), cls=ResourceOption)
     def test(**_):
-        """Test command"""
+        """Test command."""
         pass
 
     runner = CliRunner()
@@ -208,7 +205,7 @@ def test_config_dump2(tmp_path, datadir):
     )
     @verbosity_option(logging.getLogger(__name__), cls=ResourceOption)
     def test(**_):
-        """Blablabla bli blo
+        """Blablabla bli blo.
 
         Parameters
         ----------
@@ -256,7 +253,6 @@ def test_config_command_with_callback_options():
 
 
 def test_resource_option():
-
     # test usage without ConfigCommand and with entry_point_group
     @click.command()
     @click.option(
diff --git a/tests/test_config.py b/tests/test_config.py
index 5a0a77b92c67fe7b7dde8d81348d38d59ce8d838..9495832e297f3c4bd2f42fcae21bb2c077421982 100644
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -11,7 +11,6 @@ from exposed.logging import setup as logger_setup
 
 
 def test_basic(datadir):
-
     c = load([datadir / "basic_config.py"])
     assert hasattr(c, "a") and c.a == 1
     assert hasattr(c, "b") and c.b == 3
@@ -21,14 +20,12 @@ def test_basic(datadir):
 
 
 def test_empty():
-
     c = load([])
     ctx = mod_to_context(c)
     assert len(ctx) == 0
 
 
 def test_basic_with_context(datadir):
-
     c = load([datadir / "basic_config.py"], {"d": 35, "a": 0})
     assert hasattr(c, "a") and c.a == 1
     assert hasattr(c, "b") and c.b == 3
@@ -36,7 +33,6 @@ def test_basic_with_context(datadir):
 
 
 def test_chain_loading(datadir):
-
     file1 = datadir / "basic_config.py"
     file2 = datadir / "second_config.py"
     c = load([file1, file2])
@@ -45,7 +41,6 @@ def test_chain_loading(datadir):
 
 
 def test_config_with_module():
-
     c = load(
         [
             "tests.data.basic_config",
@@ -59,7 +54,6 @@ def test_config_with_module():
 
 
 def test_config_with_entry_point():
-
     c = load(
         ["first", "second", "complex"], entry_point_group="exposed.test.config"
     )
@@ -69,13 +63,11 @@ def test_config_with_entry_point():
 
 
 def test_config_with_entry_point_file_missing():
-
     with pytest.raises(ValueError):
         load(["error-config"], entry_point_group="exposed.test.config")
 
 
 def test_config_with_mixture(datadir):
-
     c = load(
         [
             datadir / "basic_config.py",
@@ -90,26 +82,22 @@ def test_config_with_mixture(datadir):
 
 
 def test_config_not_found(datadir):
-
     with pytest.raises(ValueError):
         load([datadir / "basic_config.pz"])
 
 
 def test_config_load_attribute():
-
     a = load(["tests.data.basic_config"], attribute_name="a")
     assert a == 1
 
 
 def test_config_load_no_attribute():
-
     with pytest.raises(ImportError):
         _ = load(["tests.data.basic_config"], attribute_name="wrong")
 
 
 @pytest.fixture
 def cli_messages():
-
     messages = io.StringIO()
     logger = logger_setup(
         "test-click-loading",
@@ -120,14 +108,13 @@ def cli_messages():
 
     @config_group(logger=logger, entry_point_group="exposed.test.config")
     def cli(**_):
-        """This is the documentation provided by the user"""
+        """This is the documentation provided by the user."""
         pass
 
     return (cli, messages)
 
 
 def test_config_click_config_list(cli_messages):
-
     cli = cli_messages[0]
     runner = CliRunner()
     result = runner.invoke(cli, ["list"])
@@ -137,7 +124,6 @@ def test_config_click_config_list(cli_messages):
 
 
 def test_config_click_config_list_v(cli_messages):
-
     cli = cli_messages[0]
     runner = CliRunner()
     result = runner.invoke(cli, ["list", "-v"])
@@ -148,7 +134,6 @@ def test_config_click_config_list_v(cli_messages):
 
 
 def test_config_click_config_list_vv(cli_messages):
-
     cli, messages = cli_messages
     runner = CliRunner()
     result = runner.invoke(cli, ["list", "-vv"])
@@ -160,7 +145,6 @@ def test_config_click_config_list_vv(cli_messages):
 
 
 def test_config_click_config_describe(cli_messages):
-
     cli = cli_messages[0]
     runner = CliRunner()
     result = runner.invoke(cli, ["describe", "first"])
@@ -172,7 +156,6 @@ def test_config_click_config_describe(cli_messages):
 
 
 def test_config_click_config_describe_v(cli_messages):
-
     cli = cli_messages[0]
     runner = CliRunner()
     result = runner.invoke(cli, ["describe", "first", "-v"])
@@ -183,7 +166,6 @@ def test_config_click_config_describe_v(cli_messages):
 
 
 def test_config_click_describe_error(cli_messages):
-
     cli, messages = cli_messages
     runner = CliRunner()
     result = runner.invoke(cli, ["describe", "not-found"])
@@ -194,7 +176,6 @@ def test_config_click_describe_error(cli_messages):
 
 
 def test_config_click_copy(cli_messages, datadir, tmp_path):
-
     cli = cli_messages[0]
     runner = CliRunner()
     dest = tmp_path / "file.py"
@@ -204,7 +185,6 @@ def test_config_click_copy(cli_messages, datadir, tmp_path):
 
 
 def test_config_click_copy_error(cli_messages, datadir, tmp_path):
-
     cli, messages = cli_messages
     runner = CliRunner()
     dest = tmp_path / "file.py"
diff --git a/tests/test_logging.py b/tests/test_logging.py
index 0211532b680559301feaf7a340224dab0a5ad285..1f4df73ab1c8b12a9edcb3b15d0bccb50e653c5c 100644
--- a/tests/test_logging.py
+++ b/tests/test_logging.py
@@ -11,7 +11,6 @@ from exposed.click import verbosity_option
 
 
 def test_logger_setup():
-
     lo = io.StringIO()
     hi = io.StringIO()
 
@@ -34,7 +33,6 @@ def test_logger_setup():
 
 
 def test_logger_click_no_v():
-
     lo = io.StringIO()
     hi = io.StringIO()
 
@@ -63,7 +61,6 @@ def test_logger_click_no_v():
 
 
 def test_logger_click_v():
-
     lo = io.StringIO()
     hi = io.StringIO()
 
@@ -91,7 +88,6 @@ def test_logger_click_v():
 
 
 def test_logger_click_vv():
-
     lo = io.StringIO()
     hi = io.StringIO()
 
@@ -119,7 +115,6 @@ def test_logger_click_vv():
 
 
 def test_logger_click_vvv():
-
     lo = io.StringIO()
     hi = io.StringIO()
 
@@ -147,7 +142,6 @@ def test_logger_click_vvv():
 
 
 def test_logger_click_3x_verbose():
-
     lo = io.StringIO()
     hi = io.StringIO()
 
@@ -175,7 +169,6 @@ def test_logger_click_3x_verbose():
 
 
 def test_logger_click_3x_verb():
-
     lo = io.StringIO()
     hi = io.StringIO()
 
diff --git a/tests/test_rc.py b/tests/test_rc.py
index 03f7889fb34d73ed5714a0e2c0c0ee3b78d0c01e..00297467f2330f3a683520d66ac727b04632472d 100644
--- a/tests/test_rc.py
+++ b/tests/test_rc.py
@@ -12,7 +12,6 @@ from exposed.rc import UserDefaults
 
 
 def _check_userdefaults_ex1_contents(rc):
-
     # checks that it matches the contents of that file
 
     assert rc["string"] == "this is a string"
@@ -25,7 +24,6 @@ def _check_userdefaults_ex1_contents(rc):
 
 
 def test_rc_basic_loading(datadir):
-
     # tests if we can simply read an RC file
     rc = UserDefaults(datadir / "userdefaults_ex1.cfg")
     _check_userdefaults_ex1_contents(rc)
@@ -35,7 +33,6 @@ def test_rc_basic_loading(datadir):
 
 
 def test_rc_env_loading(datadir):
-
     # tests if we can simply read an RC file
     envname = "_TEST_RC_ENV_LOADING"
     os.environ[envname] = str(datadir / "userdefaults_ex1.cfg")
@@ -45,7 +42,6 @@ def test_rc_env_loading(datadir):
 
 
 def test_rc_init_empty(tmp_path):
-
     rc = UserDefaults(tmp_path / "new-rc")
     assert not rc
 
@@ -57,7 +53,6 @@ def _check_tree(d, sect, var, val):
 
 
 def test_rc_write(tmp_path):
-
     rc = UserDefaults(tmp_path / "new-rc")
     assert not rc
 
@@ -100,7 +95,6 @@ def test_rc_write(tmp_path):
 
 
 def test_rc_delete(tmp_path):
-
     rc = UserDefaults(tmp_path / "new-rc")
     assert not rc
 
@@ -131,7 +125,6 @@ def test_rc_delete(tmp_path):
 
 
 def test_rc_backup_on_write(tmp_path):
-
     rc = UserDefaults(tmp_path / "new-rc")
     assert not rc
 
@@ -147,7 +140,6 @@ def test_rc_backup_on_write(tmp_path):
 
 
 def test_rc_clear():
-
     rc = UserDefaults("does-not-exist")
     assert not rc
 
@@ -159,7 +151,6 @@ def test_rc_clear():
 
 
 def test_rc_reload(tmp_path):
-
     rc = UserDefaults(tmp_path / "new-rc")
     rc["section1.foo"] = "bar"
     rc["section1.an_int"] = 15
@@ -179,7 +170,6 @@ def test_rc_reload(tmp_path):
 
 
 def test_rc_str(tmp_path):
-
     rc = UserDefaults(tmp_path / "new-rc")
     rc["foo"] = "bar"
     rc["section1.an_int"] = 15
@@ -189,7 +179,6 @@ def test_rc_str(tmp_path):
 
 
 def test_rc_json_legacy(datadir, tmp_path):
-
     shutil.copy(datadir / "oldjson.cfg", tmp_path)
     rc = UserDefaults(tmp_path / "oldjson.cfg")
 
@@ -201,14 +190,13 @@ def test_rc_json_legacy(datadir, tmp_path):
 
 
 def test_rc_click_loading(datadir):
-
     # tests if we can simply read an RC file
     rc = UserDefaults(datadir / "userdefaults_ex1.cfg")
     logger = logging.getLogger("test-click-loading")
 
     @user_defaults_group(logger=logger, config=rc)
     def cli(**_):
-        """This is the documentation provided by the user"""
+        """This is the documentation provided by the user."""
         pass
 
     runner = CliRunner()
@@ -241,7 +229,6 @@ def test_rc_click_loading(datadir):
 
 
 def test_rc_click_writing(datadir, tmp_path):
-
     # let's copy the user defaults to a temporary file so we can change it
     shutil.copy(datadir / "userdefaults_ex1.cfg", tmp_path)
 
@@ -250,7 +237,7 @@ def test_rc_click_writing(datadir, tmp_path):
 
     @user_defaults_group(logger=logger, config=rc)
     def cli(**_):
-        """This is the documentation provided by the user"""
+        """This is the documentation provided by the user."""
         pass
 
     runner = CliRunner()
@@ -288,7 +275,6 @@ def test_rc_click_writing(datadir, tmp_path):
 
 
 def test_rc_click_no_directory(datadir, tmp_path):
-
     # artificially removes surrounding directory to create an error
     shutil.copy(datadir / "userdefaults_ex1.cfg", tmp_path)
 
@@ -297,7 +283,7 @@ def test_rc_click_no_directory(datadir, tmp_path):
 
     @user_defaults_group(logger=logger, config=rc)
     def cli(**_):
-        """This is the documentation provided by the user"""
+        """This is the documentation provided by the user."""
         pass
 
     runner = CliRunner()
@@ -309,13 +295,12 @@ def test_rc_click_no_directory(datadir, tmp_path):
 
 
 def test_rc_click_cannot_set(tmp_path):
-
     rc = UserDefaults(tmp_path / "test.toml")
     logger = logging.getLogger("test-click-cannot-set")
 
     @user_defaults_group(logger=logger, config=rc)
     def cli(**_):
-        """This is the documentation provided by the user"""
+        """This is the documentation provided by the user."""
         pass
 
     runner = CliRunner()
@@ -332,13 +317,12 @@ def test_rc_click_cannot_set(tmp_path):
 
 
 def test_rc_click_cannot_delete(tmp_path):
-
     rc = UserDefaults(tmp_path / "test.toml")
     logger = logging.getLogger("test-click-cannot-delete")
 
     @user_defaults_group(logger=logger, config=rc)
     def cli(**_):
-        """This is the documentation provided by the user"""
+        """This is the documentation provided by the user."""
         pass
 
     runner = CliRunner()