-
-
Notifications
You must be signed in to change notification settings - Fork 148
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: A flexible way to select API operations for testing
- Loading branch information
1 parent
6987f7b
commit 74318c6
Showing
11 changed files
with
246 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import enum | ||
from typing import Any, Callable, List, Optional | ||
|
||
import attr | ||
|
||
# Indicates the most common place where filters are applied. | ||
# Other scopes are spec-specific and their filters may be applied earlier to avoid expensive computations | ||
DEFAULT_SCOPE = None | ||
|
||
|
||
class FilterResult(enum.Enum): | ||
"""The result of a single filter call. | ||
This functionality is implemented as a separate enum and not a simple boolean to provide a more descriptive API. | ||
""" | ||
|
||
INCLUDED = enum.auto() | ||
EXCLUDED = enum.auto() | ||
|
||
@property | ||
def is_included(self) -> bool: | ||
return self == FilterResult.INCLUDED | ||
|
||
@property | ||
def is_excluded(self) -> bool: | ||
return self == FilterResult.EXCLUDED | ||
|
||
def __bool__(self) -> bool: | ||
return self.is_included | ||
|
||
def __and__(self, other: "FilterResult") -> "FilterResult": | ||
if self.is_excluded or other.is_excluded: | ||
return FilterResult.EXCLUDED | ||
return self | ||
|
||
|
||
@attr.s(slots=True) | ||
class BaseFilter: | ||
func: Callable[..., bool] = attr.ib() | ||
scope: Optional[str] = attr.ib(default=DEFAULT_SCOPE) | ||
|
||
def apply(self, item: Any) -> FilterResult: | ||
raise NotImplementedError | ||
|
||
|
||
@attr.s(slots=True) | ||
class Include(BaseFilter): | ||
def apply(self, item: Any) -> FilterResult: | ||
if self.func(item): | ||
return FilterResult.INCLUDED | ||
return FilterResult.EXCLUDED | ||
|
||
|
||
@attr.s(slots=True) | ||
class Exclude(BaseFilter): | ||
def apply(self, item: Any) -> FilterResult: | ||
if self.func(item): | ||
return FilterResult.EXCLUDED | ||
return FilterResult.INCLUDED | ||
|
||
|
||
def evaluate_filters(filters: List[BaseFilter], item: Any, scope: Optional[str] = DEFAULT_SCOPE) -> FilterResult: | ||
"""Decide whether the given item passes the filters.""" | ||
# Lazily apply filters that match the given scope | ||
matching_filters = filter(lambda f: f.scope == scope, filters) | ||
outcomes = map(lambda f: f.apply(item), matching_filters) | ||
# If any filter will exclude the item, then the process short-circuits without evaluating all filters | ||
if all(outcomes): | ||
return FilterResult.INCLUDED | ||
return FilterResult.EXCLUDED |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.