Skip to content

Commit a2f0e48

Browse files
committed
Introduce Noop to make pattern non optional
1 parent f45ad46 commit a2f0e48

File tree

3 files changed

+50
-10
lines changed

3 files changed

+50
-10
lines changed

respx/models.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ def name(self, name: str) -> None:
161161
raise NotImplementedError("Can't set name on route.")
162162

163163
@property
164-
def pattern(self) -> Optional[Pattern]:
164+
def pattern(self) -> Pattern:
165165
return self._pattern
166166

167167
@pattern.setter

respx/patterns.py

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -88,13 +88,26 @@ def __init__(self, value: Any, lookup: Optional[Lookup] = None) -> None:
8888
def __iter__(self):
8989
yield self
9090

91+
def __bool__(self):
92+
return True
93+
9194
def __and__(self, other: "Pattern") -> "Pattern":
95+
if not bool(other):
96+
return self
97+
elif not bool(self):
98+
return other
9299
return _And((self, other))
93100

94101
def __or__(self, other: "Pattern") -> "Pattern":
102+
if not bool(other):
103+
return self
104+
elif not bool(self):
105+
return other
95106
return _Or((self, other))
96107

97108
def __invert__(self):
109+
if not bool(self):
110+
return self
98111
return _Invert(self)
99112

100113
def __repr__(self): # pragma: nocover
@@ -159,6 +172,22 @@ def _in(self, value: Any) -> Match:
159172
return Match(value in self.value)
160173

161174

175+
class Noop(Pattern):
176+
def __init__(self) -> None:
177+
super().__init__(None)
178+
179+
def __repr__(self):
180+
return f"<{self.__class__.__name__}>"
181+
182+
def __bool__(self) -> bool:
183+
# Treat this pattern as non-existent, e.g. when filtering or conditioning
184+
return False
185+
186+
def match(self, request: httpx.Request) -> Match:
187+
# If this pattern is part of a combined pattern, always be truthy, i.e. noop
188+
return Match(True)
189+
190+
162191
class PathPattern(Pattern):
163192
path: Optional[str]
164193

@@ -500,7 +529,7 @@ def clean(self, value: Dict) -> bytes:
500529
return data
501530

502531

503-
def M(*patterns: Pattern, **lookups: Any) -> Optional[Pattern]:
532+
def M(*patterns: Pattern, **lookups: Any) -> Pattern:
504533
extras = None
505534

506535
for pattern__lookup, value in lookups.items():
@@ -550,12 +579,10 @@ def get_scheme_port(scheme: Optional[str]) -> Optional[int]:
550579
return {"http": 80, "https": 443}.get(scheme or "")
551580

552581

553-
def combine(
554-
patterns: Sequence[Pattern], op: Callable = operator.and_
555-
) -> Optional[Pattern]:
582+
def combine(patterns: Sequence[Pattern], op: Callable = operator.and_) -> Pattern:
556583
patterns = tuple(filter(None, patterns))
557584
if not patterns:
558-
return None
585+
return Noop()
559586
return reduce(op, patterns)
560587

561588

@@ -598,14 +625,14 @@ def parse_url_patterns(
598625
return bases
599626

600627

601-
def merge_patterns(pattern: Optional[Pattern], **bases: Pattern) -> Optional[Pattern]:
628+
def merge_patterns(pattern: Pattern, **bases: Pattern) -> Pattern:
602629
if not bases:
603630
return pattern
604631

605-
if pattern:
606-
# Flatten pattern
607-
patterns = list(iter(pattern))
632+
# Flatten pattern
633+
patterns: List[Pattern] = list(filter(None, iter(pattern)))
608634

635+
if patterns:
609636
if "host" in (_pattern.key for _pattern in patterns):
610637
# Pattern is "absolute", skip merging
611638
bases = {}

tests/test_patterns.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
Lookup,
1616
M,
1717
Method,
18+
Noop,
1819
Params,
1920
Path,
2021
Pattern,
@@ -66,6 +67,18 @@ def test_match_context():
6667
assert match.context == {"host": "foo.bar", "slug": "baz"}
6768

6869

70+
def test_noop_pattern():
71+
assert bool(Noop()) is False
72+
assert bool(Noop().match(httpx.Request("GET", "https://example.org"))) is True
73+
assert list(filter(None, [Noop()])) == []
74+
assert repr(Noop()) == "<Noop>"
75+
assert isinstance(~Noop(), Noop)
76+
assert Method("GET") & Noop() == Method("GET")
77+
assert Noop() & Method("GET") == Method("GET")
78+
assert Method("GET") | Noop() == Method("GET")
79+
assert Noop() | Method("GET") == Method("GET")
80+
81+
6982
@pytest.mark.parametrize(
7083
"kwargs,url,expected",
7184
[

0 commit comments

Comments
 (0)