Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-respx for openSUSE:Factory 
checked in at 2022-10-14 15:41:25
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-respx (Old)
 and      /work/SRC/openSUSE:Factory/.python-respx.new.2275 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-respx"

Fri Oct 14 15:41:25 2022 rev:3 rq:1010383 version:0.20.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-respx/python-respx.changes        
2022-08-22 11:05:12.793712145 +0200
+++ /work/SRC/openSUSE:Factory/.python-respx.new.2275/python-respx.changes      
2022-10-14 15:42:08.363878333 +0200
@@ -1,0 +2,17 @@
+Wed Oct 12 15:57:25 UTC 2022 - Yogalakshmi Arunachalam <yarunacha...@suse.com>
+
+- Update to version 0.20.0 
+  Changed
+  * Type Router.__getitem__ to not return optional routes, thanks @flaeppe 
(#216)
+  * Change Call.response to raise instead of returning optional response (#217)
+  * Change CallList.last to raise instead of return optional call (#217)
+  * Type M() to not return optional pattern, by introducing a Noop pattern 
(#217)
+  * Type Route.pattern to not be optional (#217)
+  Fixed
+  * Correct type hints for side effects (#217)
+  Added
+  * Runs mypy on both tests and respx (#217)
+  * Added nox test session for python 3.11 (#217)
+  * Added Call.has_response helper, now that .response raises (#217)
+
+-------------------------------------------------------------------

Old:
----
  respx-0.19.2.tar.gz

New:
----
  respx-0.20.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-respx.spec ++++++
--- /var/tmp/diff_new_pack.ULOgsa/_old  2022-10-14 15:42:08.943879302 +0200
+++ /var/tmp/diff_new_pack.ULOgsa/_new  2022-10-14 15:42:08.947879308 +0200
@@ -18,7 +18,7 @@
 
 %{?!python_module:%define python_module() python3-%{**}}
 Name:           python-respx
-Version:        0.19.2
+Version:        0.20.0
 Release:        0
 Summary:        Mock HTTPX with request patterns and response side effects
 License:        BSD-3-Clause

++++++ respx-0.19.2.tar.gz -> respx-0.20.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/respx-0.19.2/CHANGELOG.md 
new/respx-0.20.0/CHANGELOG.md
--- old/respx-0.19.2/CHANGELOG.md       2022-02-03 11:16:49.000000000 +0100
+++ new/respx-0.20.0/CHANGELOG.md       2022-09-16 11:27:02.000000000 +0200
@@ -4,6 +4,36 @@
 The format is based on [Keep a 
Changelog](https://keepachangelog.com/en/1.0.0/),
 and this project adheres to [Semantic 
Versioning](https://semver.org/spec/v2.0.0.html).
 
+## [0.20.0] - 2022-09-16
+
+### Changed
+- Type Router.__getitem__ to not return optional routes, thanks @flaeppe (#216)
+- Change `Call.response` to raise instead of returning optional response (#217)
+- Change `CallList.last` to raise instead of return optional call (#217)
+- Type `M()` to not return optional pattern, by introducing a `Noop` pattern 
(#217)
+- Type `Route.pattern` to not be optional (#217)
+
+### Fixed
+- Correct type hints for side effects (#217)
+
+### Added
+- Runs `mypy` on both tests and respx (#217)
+- Added nox test session for python 3.11 (#217)
+- Added `Call.has_response` helper, now that `.response` raises (#217)
+
+## [0.19.3] - 2022-09-14
+
+### Fixed
+- Fix typing for Route modulos arg
+- Respect patterns with empty value when using equal lookup (#206)
+- Use pytest asyncio auto mode (#212)
+- Fix mock decorator to work together with pytest fixtures (#213)
+- Wrap pytest function correctly, i.e. don't hide real function name (#213)
+
+### Changed
+- Enable mypy strict_optional (#201)
+
+
 ## [0.19.2] - 2022-02-03
 
 ### Fixed
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/respx-0.19.2/docs/stylesheets/slate.css 
new/respx-0.20.0/docs/stylesheets/slate.css
--- old/respx-0.19.2/docs/stylesheets/slate.css 1970-01-01 01:00:00.000000000 
+0100
+++ new/respx-0.20.0/docs/stylesheets/slate.css 2022-09-16 11:27:02.000000000 
+0200
@@ -0,0 +1,7 @@
+[data-md-color-scheme="slate"] {
+  --md-hue: 245; 
+  --md-typeset-a-color: #9772d7;
+  --md-default-bg-color: hsla(var(--md-hue),15%,11%,1);
+  --md-footer-bg-color: hsla(var(--md-hue),15%,5%,0.87);
+  --md-footer-bg-color--dark: hsla(var(--md-hue),15%,1%,1);
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/respx-0.19.2/mkdocs.yml new/respx-0.20.0/mkdocs.yml
--- old/respx-0.19.2/mkdocs.yml 2022-02-03 11:16:49.000000000 +0100
+++ new/respx-0.20.0/mkdocs.yml 2022-09-16 11:27:02.000000000 +0200
@@ -4,11 +4,26 @@
 
 theme:
   name: "material"
-  palette:
-    primary: "deep purple"
-    accent: "deep purple"
   icon:
     logo: "material/school"
+  palette:
+    - scheme: default
+      media: "(prefers-color-scheme: light)"
+      primary: "deep purple"
+      accent: "deep purple"
+      toggle:
+        icon: material/weather-night
+        name: Switch to dark mode
+    - scheme: slate
+      media: "(prefers-color-scheme: dark)"
+      primary: "deep purple"
+      accent: "deep purple"
+      toggle:
+        icon: material/weather-sunny
+        name: Switch to light mode
+
+extra_css:
+  - stylesheets/slate.css
 
 repo_name: lundberg/respx
 repo_url: https://github.com/lundberg/respx
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/respx-0.19.2/noxfile.py new/respx-0.20.0/noxfile.py
--- old/respx-0.19.2/noxfile.py 2022-02-03 11:16:49.000000000 +0100
+++ new/respx-0.20.0/noxfile.py 2022-09-16 11:27:02.000000000 +0200
@@ -9,7 +9,7 @@
 docs_requirements = ("mkdocs", "mkdocs-material", "mkautodoc>=0.1.0")
 
 
-@nox.session(python=["3.6", "3.7", "3.8", "3.9", "3.10"])
+@nox.session(python=["3.6", "3.7", "3.8", "3.9", "3.10", "3.11"])
 def test(session):
     deps = ["pytest", "pytest-asyncio", "pytest-cov", "trio", "starlette", 
"flask"]
     session.install("--upgrade", *deps)
@@ -22,7 +22,7 @@
     session.run("pytest", "-v", *options)
 
 
-@nox.session
+@nox.session(python="3.6")
 def check(session):
     session.install("--upgrade", "flake8-bugbear", "mypy", *lint_requirements)
     session.install("-e", ".")
@@ -30,7 +30,7 @@
     session.run("black", "--check", "--diff", "--target-version=py36", 
*source_files)
     session.run("isort", "--check", "--diff", "--project=respx", *source_files)
     session.run("flake8", *source_files)
-    session.run("mypy", "respx")
+    session.run("mypy")
 
 
 @nox.session
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/respx-0.19.2/respx/__version__.py 
new/respx-0.20.0/respx/__version__.py
--- old/respx-0.19.2/respx/__version__.py       2022-02-03 11:16:49.000000000 
+0100
+++ new/respx-0.20.0/respx/__version__.py       2022-09-16 11:27:02.000000000 
+0200
@@ -1 +1 @@
-__version__ = "0.19.2"
+__version__ = "0.20.0"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/respx-0.19.2/respx/handlers.py 
new/respx-0.20.0/respx/handlers.py
--- old/respx-0.19.2/respx/handlers.py  2022-02-03 11:16:49.000000000 +0100
+++ new/respx-0.20.0/respx/handlers.py  2022-09-16 11:27:02.000000000 +0200
@@ -8,7 +8,10 @@
         self.transport = transport
 
     def __call__(self, request: httpx.Request) -> httpx.Response:
-        if not isinstance(request.stream, httpx.SyncByteStream):  # pragma: 
nocover
+        if not isinstance(
+            request.stream,  # type: ignore[has-type]
+            httpx.SyncByteStream,
+        ):  # pragma: nocover
             raise RuntimeError("Attempted to route an async request to a sync 
app.")
 
         return self.transport.handle_request(request)
@@ -19,7 +22,10 @@
         self.transport = transport
 
     async def __call__(self, request: httpx.Request) -> httpx.Response:
-        if not isinstance(request.stream, httpx.AsyncByteStream):  # pragma: 
nocover
+        if not isinstance(
+            request.stream,  # type: ignore[has-type]
+            httpx.AsyncByteStream,
+        ):  # pragma: nocover
             raise RuntimeError("Attempted to route a sync request to an async 
app.")
 
         return await self.transport.handle_async_request(request)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/respx-0.19.2/respx/models.py 
new/respx-0.20.0/respx/models.py
--- old/respx-0.19.2/respx/models.py    2022-02-03 11:16:49.000000000 +0100
+++ new/respx-0.20.0/respx/models.py    2022-09-16 11:27:02.000000000 +0200
@@ -1,16 +1,15 @@
 import inspect
 from typing import (
     Any,
-    Callable,
     Dict,
     Iterator,
     List,
     NamedTuple,
     Optional,
+    Sequence,
     Tuple,
     Type,
     Union,
-    cast,
 )
 from unittest import mock
 from warnings import warn
@@ -24,6 +23,7 @@
     HeaderTypes,
     ResolvedResponseTypes,
     RouteResultTypes,
+    SideEffectListTypes,
     SideEffectTypes,
 )
 
@@ -35,7 +35,7 @@
     response = httpx.Response(
         response.status_code,
         headers=response.headers,
-        stream=response.stream,
+        stream=response.stream,  # type: ignore[has-type]
         request=request,
         extensions=dict(response.extensions),
     )
@@ -44,30 +44,40 @@
 
 class Call(NamedTuple):
     request: httpx.Request
-    response: Optional[httpx.Response]
+    optional_response: Optional[httpx.Response]
+
+    @property
+    def response(self) -> httpx.Response:
+        if self.optional_response is None:
+            raise ValueError(f"{self!r} has no response")
+        return self.optional_response
+
+    @property
+    def has_response(self) -> bool:
+        return self.optional_response is not None
 
 
 class CallList(list, mock.NonCallableMock):
-    def __init__(self, *args, name="respx", **kwargs):
-        super().__init__(*args, **kwargs)
+    def __init__(self, *args: Sequence[Call], name: Any = "respx") -> None:
+        super().__init__(*args)
         mock.NonCallableMock.__init__(self, name=name)
 
     @property
-    def called(self) -> bool:  # type: ignore
+    def called(self) -> bool:  # type: ignore[override]
         return bool(self)
 
     @property
-    def call_count(self) -> int:  # type: ignore
+    def call_count(self) -> int:  # type: ignore[override]
         return len(self)
 
     @property
-    def last(self) -> Optional[Call]:
-        return self[-1] if self else None
+    def last(self) -> Call:
+        return self[-1]
 
     def record(
         self, request: httpx.Request, response: Optional[httpx.Response]
     ) -> Call:
-        call = Call(request=request, response=response)
+        call = Call(request=request, optional_response=response)
         self.append(call)
         return call
 
@@ -90,7 +100,9 @@
                 f"got {content!r}. Please use json=... or side effects."
             )
 
-        super().__init__(status_code or 200, content=content, **kwargs)
+        if content is not None:
+            kwargs["content"] = content
+        super().__init__(status_code or 200, **kwargs)
 
         if content_type:
             self.headers["Content-Type"] = content_type
@@ -126,7 +138,7 @@
         self.side_effect = side_effect
         return side_effect
 
-    def __mod__(self, response: Union[int, Dict[str, Any]]) -> "Route":
+    def __mod__(self, response: Union[int, Dict[str, Any], httpx.Response]) -> 
"Route":
         if isinstance(response, int):
             self.return_value = httpx.Response(status_code=response)
 
@@ -153,7 +165,7 @@
         raise NotImplementedError("Can't set name on route.")
 
     @property
-    def pattern(self) -> Optional[Pattern]:
+    def pattern(self) -> Pattern:
         return self._pattern
 
     @pattern.setter
@@ -172,15 +184,20 @@
         self._return_value = return_value
 
     @property
-    def side_effect(self) -> Optional[SideEffectTypes]:
+    def side_effect(
+        self,
+    ) -> Optional[Union[SideEffectTypes, Sequence[SideEffectListTypes]]]:
         return self._side_effect
 
     @side_effect.setter
-    def side_effect(self, side_effect: Optional[SideEffectTypes]) -> None:
+    def side_effect(
+        self,
+        side_effect: Optional[Union[SideEffectTypes, 
Sequence[SideEffectListTypes]]],
+    ) -> None:
         self.pass_through(False)
         if not side_effect:
             self._side_effect = None
-        elif isinstance(side_effect, (tuple, list, Iterator)):
+        elif isinstance(side_effect, (Iterator, Sequence)):
             self._side_effect = iter(side_effect)
         else:
             self._side_effect = side_effect
@@ -225,7 +242,9 @@
         self,
         return_value: Optional[httpx.Response] = None,
         *,
-        side_effect: Optional[SideEffectTypes] = None,
+        side_effect: Optional[
+            Union[SideEffectTypes, Sequence[SideEffectListTypes]]
+        ] = None,
     ) -> "Route":
         self.return_value = return_value
         self.side_effect = side_effect
@@ -277,14 +296,13 @@
 
     def _next_side_effect(
         self,
-    ) -> Union[Callable, Exception, Type[Exception], httpx.Response]:
-        effect: Union[Callable, Exception, Type[Exception], httpx.Response]
+    ) -> Union[CallableSideEffect, Exception, Type[Exception], httpx.Response]:
+        assert self._side_effect is not None
+        effect: Union[CallableSideEffect, Exception, Type[Exception], 
httpx.Response]
         if isinstance(self._side_effect, Iterator):
             effect = next(self._side_effect)
         else:
-            effect = cast(
-                Union[Callable, Exception, Type[Exception]], self._side_effect
-            )
+            effect = self._side_effect
 
         return effect
 
@@ -328,19 +346,18 @@
             raise SideEffectError(self, origin=effect)
 
         # Handle Exception `type` side effect
-        Error: Type[Exception] = cast(Type[Exception], effect)
-        if isinstance(effect, type) and issubclass(Error, Exception):
+        elif isinstance(effect, type) and issubclass(effect, Exception):
             raise SideEffectError(
                 self,
                 origin=(
-                    Error("Mock Error", request=request)
-                    if issubclass(Error, httpx.RequestError)
-                    else Error()
+                    effect("Mock Error", request=request)
+                    if issubclass(effect, httpx.RequestError)
+                    else effect()
                 ),
             )
 
         # Handle `Callable` side effect
-        if callable(effect):
+        elif callable(effect):
             result = self._call_side_effect(effect, request, **kwargs)
             return result
 
@@ -375,10 +392,10 @@
         Returns None for a non-matching route, mocked response for a match,
         or input request for pass-through.
         """
-        context = {}
+        context: Dict[str, Any] = {}
 
         if self._pattern:
-            match = self.pattern.match(request)
+            match = self._pattern.match(request)
             if not match:
                 return None
             context = match.context
@@ -417,7 +434,7 @@
     def __contains__(self, name: str) -> bool:
         return name in self._names
 
-    def __getitem__(self, key: Union[int, str]) -> Optional[Route]:
+    def __getitem__(self, key: Union[int, str]) -> Route:
         if isinstance(key, int):
             return self._routes[key]
         else:
@@ -427,6 +444,8 @@
         """
         Re-set all routes to given routes.
         """
+        if (i.start, i.stop, i.step) != (None, None, None):
+            raise TypeError("Can't slice assign routes")
         self._routes = list(routes._routes)
         self._names = dict(routes._names)
 
@@ -436,7 +455,7 @@
 
     def add(self, route: Route, name: Optional[str] = None) -> Route:
         # Find route with same name
-        existing_route = self._names.pop(name, None)
+        existing_route = self._names.pop(name or "", None)
 
         if route in self._routes:
             if existing_route and existing_route != route:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/respx-0.19.2/respx/patterns.py 
new/respx-0.20.0/respx/patterns.py
--- old/respx-0.19.2/respx/patterns.py  2022-02-03 11:16:49.000000000 +0100
+++ new/respx-0.20.0/respx/patterns.py  2022-09-16 11:27:02.000000000 +0200
@@ -88,13 +88,26 @@
     def __iter__(self):
         yield self
 
+    def __bool__(self):
+        return True
+
     def __and__(self, other: "Pattern") -> "Pattern":
+        if not bool(other):
+            return self
+        elif not bool(self):
+            return other
         return _And((self, other))
 
     def __or__(self, other: "Pattern") -> "Pattern":
+        if not bool(other):
+            return self
+        elif not bool(self):
+            return other
         return _Or((self, other))
 
     def __invert__(self):
+        if not bool(self):
+            return self
         return _Invert(self)
 
     def __repr__(self):  # pragma: nocover
@@ -159,6 +172,22 @@
         return Match(value in self.value)
 
 
+class Noop(Pattern):
+    def __init__(self) -> None:
+        super().__init__(None)
+
+    def __repr__(self):
+        return f"<{self.__class__.__name__}>"
+
+    def __bool__(self) -> bool:
+        # Treat this pattern as non-existent, e.g. when filtering or 
conditioning
+        return False
+
+    def match(self, request: httpx.Request) -> Match:
+        # If this pattern is part of a combined pattern, always be truthy, 
i.e. noop
+        return Match(True)
+
+
 class PathPattern(Pattern):
     path: Optional[str]
 
@@ -388,8 +417,9 @@
         return request.url.path
 
     def strip_base(self, value: str) -> str:
-        value = value[len(self.base.value) :]
-        value = "/" + value if not value.startswith("/") else value
+        if self.base:
+            value = value[len(self.base.value) :]
+            value = "/" + value if not value.startswith("/") else value
         return value
 
 
@@ -503,9 +533,6 @@
     extras = None
 
     for pattern__lookup, value in lookups.items():
-        if not value:
-            continue
-
         # Handle url pattern
         if pattern__lookup == "url":
             extras = parse_url_patterns(value)
@@ -534,6 +561,10 @@
             lookup = Lookup(lookup_name) if lookup_name else None
             pattern = P(value, lookup=lookup)
 
+        # Skip patterns with no value, exept when using equal lookup
+        if not pattern.value and pattern.lookup is not Lookup.EQUAL:
+            continue
+
         patterns += (pattern,)
 
     # Combine and merge patterns
@@ -545,15 +576,13 @@
 
 
 def get_scheme_port(scheme: Optional[str]) -> Optional[int]:
-    return {"http": 80, "https": 443}.get(scheme)
+    return {"http": 80, "https": 443}.get(scheme or "")
 
 
-def combine(
-    patterns: Sequence[Pattern], op: Callable = operator.and_
-) -> Optional[Pattern]:
+def combine(patterns: Sequence[Pattern], op: Callable = operator.and_) -> 
Pattern:
     patterns = tuple(filter(None, patterns))
     if not patterns:
-        return None
+        return Noop()
     return reduce(op, patterns)
 
 
@@ -600,13 +629,13 @@
     if not bases:
         return pattern
 
-    if pattern:
-        # Flatten pattern
-        patterns = list(iter(pattern))
+    # Flatten pattern
+    patterns: List[Pattern] = list(filter(None, iter(pattern)))
 
+    if patterns:
         if "host" in (_pattern.key for _pattern in patterns):
             # Pattern is "absolute", skip merging
-            bases = None
+            bases = {}
         else:
             # Traverse pattern and set related base
             for _pattern in patterns:
@@ -619,7 +648,7 @@
     if bases:
         # Combine left over base patterns with pattern
         base_pattern = combine(list(bases.values()))
-        if pattern:
+        if pattern and base_pattern:
             pattern = base_pattern & pattern
         else:
             pattern = base_pattern
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/respx-0.19.2/respx/router.py 
new/respx-0.20.0/respx/router.py
--- old/respx-0.19.2/respx/router.py    2022-02-03 11:16:49.000000000 +0100
+++ new/respx-0.20.0/respx/router.py    2022-09-16 11:27:02.000000000 +0200
@@ -1,6 +1,6 @@
 import inspect
 from contextlib import contextmanager
-from functools import update_wrapper
+from functools import partial, update_wrapper, wraps
 from types import TracebackType
 from typing import (
     Any,
@@ -283,7 +283,9 @@
                     resolved.response = cast(ResolvedResponseTypes, prospect)
                     break
 
-        if isinstance(resolved.response.stream, httpx.ByteStream):
+        if resolved.response and isinstance(
+            resolved.response.stream, httpx.ByteStream  # type: 
ignore[has-type]
+        ):
             resolved.response.read()  # Pre-read stream
 
         return resolved
@@ -305,7 +307,9 @@
                     resolved.response = cast(ResolvedResponseTypes, prospect)
                     break
 
-        if isinstance(resolved.response.stream, httpx.ByteStream):
+        if resolved.response and isinstance(
+            resolved.response.stream, httpx.ByteStream  # type: 
ignore[has-type]
+        ):
             await resolved.response.aread()  # Pre-read stream
 
         return resolved
@@ -322,8 +326,6 @@
 
 
 class MockRouter(Router):
-    Mocker: Optional[Type[Mocker]]
-
     def __init__(
         self,
         *,
@@ -337,6 +339,7 @@
             assert_all_mocked=assert_all_mocked,
             base_url=base_url,
         )
+        self.Mocker: Optional[Type[Mocker]] = None
         self._using = using
 
     @overload
@@ -395,33 +398,36 @@
             return respx_mock
 
         # Determine if decorated function needs a `respx_mock` instance
+        is_async = inspect.iscoroutinefunction(func)
         argspec = inspect.getfullargspec(func)
         needs_mock_reference = "respx_mock" in argspec.args
 
+        if needs_mock_reference:
+            func = partial(func, respx_mock=self)
+
         # Async Decorator
-        async def async_decorator(*args, **kwargs):
+        async def _async_decorator(*args, **kwargs):
             assert func is not None
-            if needs_mock_reference:
-                kwargs["respx_mock"] = self
             async with self:
                 return await func(*args, **kwargs)
 
         # Sync Decorator
-        def sync_decorator(*args, **kwargs):
+        def _sync_decorator(*args, **kwargs):
             assert func is not None
-            if "respx_mock" in argspec.args:
-                kwargs["respx_mock"] = self
             with self:
                 return func(*args, **kwargs)
 
-        if not needs_mock_reference:
-            async_decorator = update_wrapper(async_decorator, func)
-            sync_decorator = update_wrapper(sync_decorator, func)
+        if needs_mock_reference:
+            async_decorator = wraps(func)(_async_decorator)
+            sync_decorator = wraps(func)(_sync_decorator)
+        else:
+            async_decorator = update_wrapper(_async_decorator, func)
+            sync_decorator = update_wrapper(_sync_decorator, func)
 
         # Dispatch async/sync decorator, depending on decorated function.
         # - Only stage when using global decorator `@respx.mock`
         # - Second stage when using local decorator `@respx.mock(...)`
-        return async_decorator if inspect.iscoroutinefunction(func) else 
sync_decorator
+        return async_decorator if is_async else sync_decorator
 
     def __enter__(self) -> "MockRouter":
         self.start()
@@ -429,9 +435,9 @@
 
     def __exit__(
         self,
-        exc_type: Type[BaseException] = None,
-        exc_value: BaseException = None,
-        traceback: TracebackType = None,
+        exc_type: Optional[Type[BaseException]] = None,
+        exc_value: Optional[BaseException] = None,
+        traceback: Optional[TracebackType] = None,
     ) -> None:
         self.stop(quiet=bool(exc_type is not None))
 
@@ -461,7 +467,7 @@
         Register transport, snapshot router and start patching.
         """
         self.snapshot()
-        self.Mocker = Mocker.registry.get(self.using)
+        self.Mocker = Mocker.registry.get(self.using or "")
         if self.Mocker:
             self.Mocker.register(self)
             self.Mocker.start()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/respx-0.19.2/respx/transports.py 
new/respx-0.20.0/respx/transports.py
--- old/respx-0.19.2/respx/transports.py        2022-02-03 11:16:49.000000000 
+0100
+++ new/respx-0.20.0/respx/transports.py        2022-09-16 11:27:02.000000000 
+0200
@@ -55,9 +55,9 @@
 
     def __exit__(
         self,
-        exc_type: Type[BaseException] = None,
-        exc_value: BaseException = None,
-        traceback: TracebackType = None,
+        exc_type: Optional[Type[BaseException]] = None,
+        exc_value: Optional[BaseException] = None,
+        traceback: Optional[TracebackType] = None,
     ) -> None:
         if not exc_type and self._router and self._router._assert_all_called:
             self._router.assert_all_called()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/respx-0.19.2/respx/types.py 
new/respx-0.20.0/respx/types.py
--- old/respx-0.19.2/respx/types.py     2022-02-03 11:16:49.000000000 +0100
+++ new/respx-0.20.0/respx/types.py     2022-09-16 11:27:02.000000000 +0200
@@ -51,6 +51,5 @@
     CallableSideEffect,
     Exception,
     Type[Exception],
-    Sequence[SideEffectListTypes],
     Iterator[SideEffectListTypes],
 ]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/respx-0.19.2/setup.cfg new/respx-0.20.0/setup.cfg
--- old/respx-0.19.2/setup.cfg  2022-02-03 11:16:49.000000000 +0100
+++ new/respx-0.20.0/setup.cfg  2022-09-16 11:27:02.000000000 +0200
@@ -3,7 +3,7 @@
 
 [flake8]
 max-line-length = 88
-ignore = E501,E266,E731,W503,E203
+ignore = E501,E266,E731,W503,E203,B024
 exclude = .git
 show-source = true
 
@@ -25,6 +25,7 @@
     --cov-report=xml
     --cov-fail-under 100
     -rxXs
+asyncio_mode = auto
 
 [coverage:run]
 source = respx,tests
@@ -35,10 +36,14 @@
 show_missing = True
 
 [mypy]
+python_version = 3.6
+files = respx,tests
+pretty = True
+
 no_implicit_reexport = True
 no_implicit_optional = True
 strict_equality = True
-strict_optional = False
+strict_optional = True
 check_untyped_defs = True
 disallow_incomplete_defs = True
 ignore_missing_imports = False
@@ -48,5 +53,16 @@
 warn_unused_ignores = True
 warn_unreachable = True
 
+show_error_codes = True
+
 [mypy-pytest.*]
 ignore_missing_imports = True
+
+[mypy-trio.*]
+ignore_missing_imports = True
+
+[mypy-flask.*]
+ignore_missing_imports = True
+
+[mypy-starlette.*]
+ignore_missing_imports = True
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/respx-0.19.2/tests/test_api.py 
new/respx-0.20.0/tests/test_api.py
--- old/respx-0.19.2/tests/test_api.py  2022-02-03 11:16:49.000000000 +0100
+++ new/respx-0.20.0/tests/test_api.py  2022-09-16 11:27:02.000000000 +0200
@@ -99,7 +99,7 @@
 async def test_invalid_url_pattern():
     async with MockRouter() as respx_mock:
         with pytest.raises(TypeError):
-            respx_mock.get(["invalid"])
+            respx_mock.get(["invalid"])  # type: ignore[arg-type]
 
 
 @pytest.mark.asyncio
@@ -277,7 +277,10 @@
     async with MockRouter() as respx_mock:
         url = "https://foo.bar/";
         request = respx_mock.get(url)
-        request.side_effect = httpx.ConnectTimeout("X-P", request=None)
+        request.side_effect = httpx.ConnectTimeout(
+            "X-P",
+            request=None,  # type: ignore[arg-type]
+        )
         with pytest.raises(httpx.ConnectTimeout):
             await client.get(url)
 
@@ -293,7 +296,9 @@
 
         assert route.call_count == 2
         assert route.calls.last.request is not None
-        assert route.calls.last.response is None
+        assert route.calls.last.has_response is False
+        with pytest.raises(ValueError, match="has no response"):
+            assert route.calls.last.response
 
 
 @pytest.mark.asyncio
@@ -303,7 +308,7 @@
 
         def content_callback(request, slug):
             content = jsonlib.loads(request.content)
-            return respx.MockResponse(text=f"hello {slug}{content['x']}")
+            return respx.MockResponse(content=f"hello {slug}{content['x']}")
 
         request = respx_mock.post(url_pattern)
         request.side_effect = content_callback
@@ -356,7 +361,9 @@
         assert response.text == "hello lundberg"
 
         with pytest.raises(TypeError):
-            respx_mock.get("https://ham.spam/";).mock(side_effect=lambda req: 
"invalid")
+            respx_mock.get("https://ham.spam/";).mock(
+                side_effect=lambda req: "invalid"  # type: 
ignore[arg-type,return-value]
+            )
             await client.get("https://ham.spam/";)
 
         with pytest.raises(httpx.NetworkError):
@@ -526,10 +533,10 @@
         assert respx.routes["foobar"].called
 
         with pytest.raises(TypeError):
-            respx.add(route, status_code=418)  # pragma: nocover
+            respx.add(route, status_code=418)  # type: ignore[call-arg]
 
         with pytest.raises(ValueError):
-            respx.add("GET")  # pragma: nocover
+            respx.add("GET")  # type: ignore[arg-type]
 
         with pytest.raises(NotImplementedError):
             route.name = "spam"
@@ -554,7 +561,7 @@
             route.respond(content={})
 
         with pytest.raises(TypeError, match="content can only be"):
-            route.respond(content=Exception())
+            route.respond(content=Exception())  # type: ignore[arg-type]
 
 
 @pytest.mark.asyncio
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/respx-0.19.2/tests/test_mock.py 
new/respx-0.20.0/tests/test_mock.py
--- old/respx-0.19.2/tests/test_mock.py 2022-02-03 11:16:49.000000000 +0100
+++ new/respx-0.20.0/tests/test_mock.py 2022-09-16 11:27:02.000000000 +0200
@@ -299,6 +299,14 @@
 
 
 @pytest.mark.asyncio
+@respx.mock(base_url="https://foo.bar";)
+async def test_configured_decorator_with_fixture(respx_mock, client):
+    respx_mock.get("/")
+    response = await client.get("https://foo.bar/";)
+    assert response.status_code == 200
+
+
+@pytest.mark.asyncio
 async def test_configured_router_reuse(client):
     router = respx.mock()
     route = router.get("https://foo/bar/";) % 404
@@ -309,25 +317,25 @@
     with router:
         route.return_value = httpx.Response(202)
         response = await client.get("https://foo/bar/";)
-        assert route.called is True
+        assert route.called == True  # noqa: E712
         assert response.status_code == 202
         assert router.calls.call_count == 1
         assert respx.calls.call_count == 0
 
     assert len(router.routes) == 1
-    assert route.called is False
+    assert route.called == False  # noqa: E712
     assert router.calls.call_count == 0
 
     async with router:
         assert router.calls.call_count == 0
         response = await client.get("https://foo/bar/";)
-        assert route.called is True
+        assert route.called == True  # noqa: E712
         assert response.status_code == 404
         assert router.calls.call_count == 1
         assert respx.calls.call_count == 0
 
     assert len(router.routes) == 1
-    assert route.called is False
+    assert route.called == False  # noqa: E712
     assert router.calls.call_count == 0
     assert respx.calls.call_count == 0
 
@@ -338,7 +346,7 @@
     route = router.get("https://hot.dog/";)
 
     with pytest.raises(TypeError):
-        route.return_value = "not-a-httpx-response"
+        route.return_value = "not-a-httpx-response"  # type: ignore[assignment]
 
 
 @pytest.mark.asyncio
@@ -388,7 +396,7 @@
     try:
         respx.start()
         response = await client.get(url)
-        assert request.called is True
+        assert request.called == True  # noqa: E712
         assert response.status_code == 202
         assert response.text == ""
         assert respx.calls.call_count == 1
@@ -396,12 +404,12 @@
         respx.stop(clear=False, reset=False)
         assert len(respx.routes) == 1
         assert respx.calls.call_count == 1
-        assert request.called is True
+        assert request.called == True  # noqa: E712
 
         respx.reset()
         assert len(respx.routes) == 1
         assert respx.calls.call_count == 0
-        assert request.called is False
+        assert request.called == False  # noqa: E712
 
         respx.clear()
         assert len(respx.routes) == 0
@@ -537,7 +545,7 @@
 
 def test_router_using__invalid():
     with pytest.raises(ValueError, match="using"):
-        respx.MockRouter(using=123).using
+        respx.MockRouter(using=123).using  # type: ignore[arg-type]
 
 
 def test_mocker_subclass():
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/respx-0.19.2/tests/test_patterns.py 
new/respx-0.20.0/tests/test_patterns.py
--- old/respx-0.19.2/tests/test_patterns.py     2022-02-03 11:16:49.000000000 
+0100
+++ new/respx-0.20.0/tests/test_patterns.py     2022-09-16 11:27:02.000000000 
+0200
@@ -15,6 +15,7 @@
     Lookup,
     M,
     Method,
+    Noop,
     Params,
     Path,
     Pattern,
@@ -66,6 +67,31 @@
     assert match.context == {"host": "foo.bar", "slug": "baz"}
 
 
+def test_noop_pattern():
+    assert bool(Noop()) is False
+    assert bool(Noop().match(httpx.Request("GET", "https://example.org";))) is 
True
+    assert list(filter(None, [Noop()])) == []
+    assert repr(Noop()) == "<Noop>"
+    assert isinstance(~Noop(), Noop)
+    assert Method("GET") & Noop() == Method("GET")
+    assert Noop() & Method("GET") == Method("GET")
+    assert Method("GET") | Noop() == Method("GET")
+    assert Noop() | Method("GET") == Method("GET")
+
+
+@pytest.mark.parametrize(
+    "kwargs,url,expected",
+    [
+        ({"params__eq": {}}, "https://foo.bar/";, True),
+        ({"params__eq": {}}, "https://foo.bar/?x=y";, False),
+        ({"params__contains": {}}, "https://foo.bar/?x=y";, True),
+    ],
+)
+def test_m_pattern(kwargs, url, expected):
+    request = httpx.Request("GET", url)
+    assert bool(M(host="foo.bar", **kwargs).match(request)) is expected
+
+
 @pytest.mark.parametrize(
     "lookup,value,expected",
     [
@@ -191,6 +217,11 @@
     request = httpx.Request("GET", "https://foo.bar/baz/";)
     assert Path(["/egg/", "/baz/"], lookup=Lookup.IN).match(request)
 
+    path = Path("/bar/")
+    assert path.strip_base("/foo/bar/") == "/foo/bar/"
+    path.base = Path("/foo/")
+    assert path.strip_base("/foo/bar/") == "/bar/"
+
 
 @pytest.mark.parametrize(
     "lookup,params,url,expected",
@@ -212,6 +243,8 @@
         (Lookup.EQUAL, "y=2", "https://foo.bar/?x=1";, False),
         (Lookup.EQUAL, {"x": ANY}, "https://foo.bar/?x=1";, True),
         (Lookup.EQUAL, {"y": ANY}, "https://foo.bar/?x=1";, False),
+        (Lookup.EQUAL, {}, "https://foo.bar/?x=1";, False),
+        (Lookup.EQUAL, {}, "https://foo.bar/";, True),
         (Lookup.EQUAL, "x=1&y=2", "https://foo.bar/?x=1";, False),
         (Lookup.EQUAL, "y=2&x=1", "https://foo.bar/?x=1&y=2";, True),
         (Lookup.EQUAL, "y=3&x=2&x=1", "https://foo.bar/?x=1&x=2&y=3";, False),  
# ordered
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/respx-0.19.2/tests/test_plugin.py 
new/respx-0.20.0/tests/test_plugin.py
--- old/respx-0.19.2/tests/test_plugin.py       2022-02-03 11:16:49.000000000 
+0100
+++ new/respx-0.20.0/tests/test_plugin.py       2022-09-16 11:27:02.000000000 
+0200
@@ -4,6 +4,9 @@
         import httpx
         import pytest
 
+        @pytest.fixture
+        def some_fixture():
+            yield "foobar"
 
         def test_plain_fixture(respx_mock):
             route = respx_mock.get("https://foo.bar/";) % 204
@@ -18,7 +21,20 @@
             assert response.status_code == 204
             response = httpx.get("https://example.org/";)
             assert response.status_code == 200
+
+
+        def test_with_extra_fixture(respx_mock, some_fixture):
+            import respx
+            assert isinstance(respx_mock, respx.Router)
+            assert some_fixture == "foobar"
+
+
+        @pytest.mark.respx(assert_all_mocked=False)
+        def test_marked_with_extra_fixture(respx_mock, some_fixture):
+            import respx
+            assert isinstance(respx_mock, respx.Router)
+            assert some_fixture == "foobar"
         """
     )
     result = testdir.runpytest("-p", "respx")
-    result.assert_outcomes(passed=2)
+    result.assert_outcomes(passed=4)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/respx-0.19.2/tests/test_remote.py 
new/respx-0.20.0/tests/test_remote.py
--- old/respx-0.19.2/tests/test_remote.py       2022-02-03 11:16:49.000000000 
+0100
+++ new/respx-0.20.0/tests/test_remote.py       2022-09-16 11:27:02.000000000 
+0200
@@ -37,7 +37,7 @@
         assert response.json()["json"] == {"foo": "bar"}
 
         assert respx_mock.calls.last.request.url == url
-        assert respx_mock.calls.last.response is None
+        assert respx_mock.calls.last.has_response is False
 
         assert route.call_count == call_count
         assert respx_mock.calls.call_count == call_count
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/respx-0.19.2/tests/test_router.py 
new/respx-0.20.0/tests/test_router.py
--- old/respx-0.19.2/tests/test_router.py       2022-02-03 11:16:49.000000000 
+0100
+++ new/respx-0.20.0/tests/test_router.py       2022-09-16 11:27:02.000000000 
+0200
@@ -29,11 +29,13 @@
     resolved = router.resolve(request)
 
     assert resolved.route is None
+    assert isinstance(resolved.response, httpx.Response)
     assert resolved.response.status_code == 200
 
     resolved = await router.aresolve(request)
 
     assert resolved.route is None
+    assert isinstance(resolved.response, httpx.Response)
     assert resolved.response.status_code == 200
 
 
@@ -62,6 +64,7 @@
     resolved = router.resolve(request)
 
     assert bool(resolved.route is route) is expected
+    assert isinstance(resolved.response, httpx.Response)
     if expected:
         assert bool(resolved.response.status_code == 201) is expected
     else:
@@ -82,6 +85,7 @@
     route.pass_through(False)
     resolved = router.resolve(request)
 
+    assert resolved.route is not None
     assert resolved.route is route
     assert not resolved.route.is_pass_through
     assert resolved.response is not None
@@ -106,6 +110,7 @@
     resolved = router.resolve(request)
 
     assert bool(resolved.route is route) is expected
+    assert isinstance(resolved.response, httpx.Response)
     if expected:
         assert bool(resolved.response.status_code == 201) is expected
     else:
@@ -151,23 +156,26 @@
 
     request = httpx.Request("GET", "https://foo.bar/baz/";)
     resolved = router.resolve(request)
+    assert isinstance(resolved.response, httpx.Response)
     assert resolved.response.status_code == 404
     assert resolved.route is route1b
     assert route1a is route1b
 
     request = httpx.Request("GET", "https://foo.bar/";)
     resolved = router.resolve(request)
+    assert isinstance(resolved.response, httpx.Response)
     assert resolved.response.status_code == 201
     assert resolved.route is route2
 
     request = httpx.Request("POST", "https://fox.zoo/";)
     resolved = router.resolve(request)
+    assert isinstance(resolved.response, httpx.Response)
     assert resolved.response.status_code == 401
     assert resolved.response.json() == {"error": "x"}
     assert resolved.route is route3
 
     with pytest.raises(TypeError, match="Route can only"):
-        router.route() % []
+        router.route() % []  # type: ignore[operator]
 
 
 @pytest.mark.asyncio
@@ -197,7 +205,7 @@
     request = httpx.Request("GET", "https://foo.bar/baz/";)
     response = router.handler(request)
     assert response.status_code == 204
-    assert response.request.respx_was_here is True
+    assert response.request.respx_was_here is True  # type: 
ignore[attr-defined]
 
 
 def test_side_effect_with_route_kwarg():
@@ -379,12 +387,12 @@
 
     assert len(router.routes) == 1
     assert router.calls.call_count == 0
-    assert route.return_value is None
+    assert route.return_value == None  # noqa: E711
 
     router.rollback()  # Empty initial state
 
     assert len(router.routes) == 0
-    assert route.return_value is None
+    assert route.return_value == None  # noqa: E711
 
     # Idempotent
     route.rollback()
@@ -523,3 +531,9 @@
     routes.add(foobar2, name="foobar")
     assert list(routes) == [foobar2]
     assert routes["foobar"] is foobar1
+
+
+def test_routelist__unable_to_slice_assign():
+    routes = RouteList()
+    with pytest.raises(TypeError, match="slice assign"):
+        routes[0:1] = routes
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/respx-0.19.2/tests/test_stats.py 
new/respx-0.20.0/tests/test_stats.py
--- old/respx-0.19.2/tests/test_stats.py        2022-02-03 11:16:49.000000000 
+0100
+++ new/respx-0.20.0/tests/test_stats.py        2022-09-16 11:27:02.000000000 
+0200
@@ -18,7 +18,7 @@
 
 
 @respx.mock
-async def backend_test(backend):
+async def backend_test():
     url = "https://foo.bar/1/";
     respx.get(re.compile("https://some.thing";))
     respx.delete("https://some.thing";)
@@ -26,10 +26,11 @@
     foobar1 = respx.get(url, name="get_foobar") % dict(status_code=202, 
text="get")
     foobar2 = respx.delete(url, name="del_foobar") % dict(text="del")
 
-    assert foobar1.called is False
+    assert foobar1.called == False  # noqa: E712
     assert foobar1.call_count == len(foobar1.calls)
     assert foobar1.call_count == 0
-    assert foobar1.calls.last is None
+    with pytest.raises(IndexError):
+        foobar1.calls.last
     assert respx.calls.call_count == len(respx.calls)
     assert respx.calls.call_count == 0
 
@@ -43,8 +44,8 @@
         get_response = await client.get(url)
         del_response = await client.delete(url)
 
-    assert foobar1.called is True
-    assert foobar2.called is True
+    assert foobar1.called == True  # noqa: E712
+    assert foobar2.called == True  # noqa: E712
     assert foobar1.call_count == 1
     assert foobar2.call_count == 1
     assert foobar1.calls.call_count == 1
@@ -92,19 +93,14 @@
 def test_asyncio():
     import asyncio
 
-    from httpcore.backends.asyncio import AsyncIOBackend
-
-    backend = AsyncIOBackend()  # TODO: Why instantiate a backend?
     loop = asyncio.new_event_loop()
     try:
-        loop.run_until_complete(backend_test(backend))
+        loop.run_until_complete(backend_test())
     finally:
         loop.close()
 
 
 def test_trio():  # pragma: nocover
     import trio
-    from httpcore.backends.trio import TrioBackend
 
-    backend = TrioBackend()  # TODO: Why instantiate a backend?
-    trio.run(backend_test, backend)
+    trio.run(backend_test)

Reply via email to