Skip to content

Commit

Permalink
use runtime module protocol checks
Browse files Browse the repository at this point in the history
  • Loading branch information
zkurtz committed Nov 29, 2024
1 parent 6e0d318 commit 5e8b5c4
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 23 deletions.
1 change: 0 additions & 1 deletion dummio/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

from dummio import json as json
from dummio import text as text
from dummio.constants import ModuleProtocol as ModuleProtocol

try:
from dummio import yaml as yaml
Expand Down
20 changes: 1 addition & 19 deletions dummio/constants.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,10 @@
"""Constants for dummio."""

import typing
from pathlib import Path
from typing import Any, Protocol, TypeAlias
from typing import Any, TypeAlias

PathType: TypeAlias = str | Path
AnyDict: TypeAlias = dict[Any, Any]

# pyright expect a type var to be used at least twice within a single method. It's having
# trouble respecting how it's use *accross* methods of a class.
T = typing.TypeVar("T") # pyright: ignore

DEFAULT_ENCODING = "utf-8"
DEFAULT_WRITE_MODE = "w"


@typing.runtime_checkable
class ModuleProtocol(Protocol):
"""Protocol for dummio's IO modules."""

def save(self, data: T, *, filepath: PathType) -> None: # pyright: ignore[reportInvalidTypeVarUse]
"""Declares the signature of an IO module save method."""
...

def load(self, filepath: PathType) -> T: # pyright: ignore[reportInvalidTypeVarUse]
"""Declares the signature of an IO module load method."""
...
30 changes: 27 additions & 3 deletions tests/test_assert_module_protocol.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
"""Assert that every IO module implements the ModuleProtocol."""
"""Assert that every IO module implements save and load in a consistent way."""

import importlib
from typing import Callable, get_type_hints

from dummio import ModuleProtocol
from dummio.constants import PathType

IO_MODULES = [
"dummio.json",
Expand All @@ -17,4 +18,27 @@
def test_assert_module_protocol() -> None:
for module_name in IO_MODULES:
module = importlib.import_module(module_name)
assert isinstance(module, ModuleProtocol)
assert hasattr(module, "save")
assert hasattr(module, "load")

# make the following assertions about the save attribute:
# - it is a function
# - the first argument is named "data"
# - all subsequent arguments are keyword-only
# - the second argument is "filepath" of type dummio.constants.PathType
assert isinstance(module.save, Callable)
signature = get_type_hints(module.save)
first_two_args = list(signature.keys())[:2]
assert first_two_args == ["data", "filepath"]
assert signature["filepath"] == PathType

# make the following assertions about the load attribute:
# - it is a function
# - the first argument is named "filepath", of type dummio.constants.PathType
# - the return type is the same as the "data" argument of the save function
assert isinstance(module.load, Callable)
signature = get_type_hints(module.load)
first_arg = list(signature.keys())[0]
assert first_arg == "filepath"
assert signature["filepath"] == PathType
assert signature["return"] == get_type_hints(module.save)["data"]

0 comments on commit 5e8b5c4

Please sign in to comment.