Skip to content

Commit

Permalink
Make FilterCompatible less ambiguous (for now) 🔞
Browse files Browse the repository at this point in the history
  • Loading branch information
todofixthis committed Oct 19, 2024
1 parent 5908247 commit c2c881b
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 38 deletions.
3 changes: 1 addition & 2 deletions src/filters/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# Note that the order is important here, due to dependencies.
# Additional filters are loaded into a separate namespace, so that IDEs
# don't go insane.
from .base import Type
from .base import NoOp, Type
from .complex import (
FilterMapper,
FilterRepeater,
Expand All @@ -28,7 +28,6 @@
Length,
MaxLength,
MinLength,
NoOp,
NotEmpty,
Omit,
Optional,
Expand Down
51 changes: 29 additions & 22 deletions src/filters/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,18 @@
"FilterChain",
"FilterCompatible",
"FilterError",
"NoOp",
"Type",
]

T = typing.TypeVar("T")
U = typing.TypeVar("U")

FilterCompatible = (
typing.Union[
"BaseFilter[T]",
typing.Callable[[], "BaseFilter[T]"],
]
| None
)
FilterCompatible = typing.Union[
"BaseFilter[T]",
"typing.Callable[..., BaseFilter[T]]",
None,
]
"""
Used in PEP-484 type hints to indicate a value that can be normalized
into an instance of a :py:class:`filters.base.BaseFilter` subclass.
Expand Down Expand Up @@ -95,7 +94,7 @@ def __or__(self, next_filter: FilterCompatible) -> "FilterChain[T]":
"""
Chains another filter with this one.
"""
normalized = self.resolve_filter(next_filter)
normalized = self.resolve(next_filter)

if normalized:
#
Expand Down Expand Up @@ -274,7 +273,7 @@ def _filter(
Appended to the ``key`` value in the error message context
(used by complex filters).
"""
filter_chain = self.resolve_filter(
filter_chain = self.resolve(
filter_chain,
parent=self,
key=sub_key,
Expand Down Expand Up @@ -398,12 +397,14 @@ def _format_message(
return self.templates[key].format(**template_vars)

@classmethod
def resolve_filter(
def resolve(
cls,
the_filter: FilterCompatible,
the_filter: typing.Union[
"BaseFilter[U]", typing.Callable[[], "BaseFilter[U]"], None
],
parent: "BaseFilter[typing.Any] | None" = None,
key: str | None = None,
) -> "FilterChain[U] | None":
) -> "BaseFilter[U]":
"""
Converts a filter-compatible value into a consistent type.
"""
Expand All @@ -412,17 +413,13 @@ def resolve_filter(
resolved = the_filter

elif callable(the_filter):
resolved = cls.resolve_filter(the_filter())
resolved = cls.resolve(the_filter())

# Uhh... hm.
else:
raise TypeError(
"{type} {value!r} is not "
"compatible with {target}.".format(
type=type(the_filter).__name__,
value=the_filter,
target=cls.__name__,
),
f"{type(the_filter).__name__} {the_filter!r} "
f"is not compatible with {cls.__name__}."
)

if parent:
Expand All @@ -433,7 +430,7 @@ def resolve_filter(

return resolved

return None
return NoOp[U]()

@staticmethod
def _make_key(key_parts: typing.Iterable[str]) -> str:
Expand Down Expand Up @@ -472,7 +469,7 @@ def __or__(self, next_filter: FilterCompatible) -> "FilterChain[U]":
This method creates a new FilterChain object without modifying
the current one.
"""
resolved = self.resolve_filter(next_filter)
resolved = self.resolve(next_filter)

if resolved:
new_chain: FilterChain[U] = copy(self)
Expand All @@ -495,7 +492,7 @@ def _add(self, next_filter: FilterCompatible) -> "FilterChain":
"""
Adds a Filter to the collection directly.
"""
resolved = self.resolve_filter(next_filter, parent=self)
resolved = self.resolve(next_filter, parent=self)
if resolved:
self._filters.append(resolved)

Expand Down Expand Up @@ -591,6 +588,16 @@ def handle_invalid_value(
raise error


class NoOp(BaseFilter[T]):
"""
Filter that does nothing, used when you need a placeholder Filter in a
FilterChain.
"""

def _apply(self, value):
return value


# This filter is used extensively by other filters.
# To avoid lots of needless "circular import" hacks, we'll put it in
# the base module.
Expand Down
4 changes: 2 additions & 2 deletions src/filters/complex.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def __init__(
"""
super().__init__()

self._filter_chain = self.resolve_filter(filter_chain, parent=self)
self._filter_chain = self.resolve(filter_chain, parent=self)

self.restrict_keys = None if restrict_keys is None else set(restrict_keys)

Expand Down Expand Up @@ -235,7 +235,7 @@ def __init__(
# (depending on `allow_missing_keys`) without
# applying any Filters to the value.
#
self._filters[key] = self.resolve_filter(
self._filters[key] = self.resolve(
filter_chain,
parent=self,
key=key,
Expand Down
2 changes: 1 addition & 1 deletion src/filters/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ def __init__(
"""
super().__init__()

self.filter_chain = BaseFilter.resolve_filter(starting_filter)
self.filter_chain = BaseFilter.resolve(starting_filter)
self.data = incoming_data
self.capture_exc_info = capture_exc_info

Expand Down
11 changes: 0 additions & 11 deletions src/filters/simple.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
"Length",
"MaxLength",
"MinLength",
"NoOp",
"NotEmpty",
"Omit",
"Optional",
Expand Down Expand Up @@ -612,16 +611,6 @@ def _apply(self, value):
return value


class NoOp(BaseFilter[T]):
"""
Filter that does nothing, used when you need a placeholder Filter in a
FilterChain.
"""

def _apply(self, value):
return value


class NotEmpty(BaseFilter[T]):
"""
Expects the value not to be empty.
Expand Down

0 comments on commit c2c881b

Please sign in to comment.