Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-anyio for openSUSE:Factory 
checked in at 2024-03-14 17:42:27
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-anyio (Old)
 and      /work/SRC/openSUSE:Factory/.python-anyio.new.1905 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-anyio"

Thu Mar 14 17:42:27 2024 rev:20 rq:1157062 version:4.3.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-anyio/python-anyio.changes        
2024-01-21 23:07:44.088146221 +0100
+++ /work/SRC/openSUSE:Factory/.python-anyio.new.1905/python-anyio.changes      
2024-03-14 17:42:35.319941817 +0100
@@ -1,0 +2,14 @@
+Mon Mar 11 23:36:15 UTC 2024 - Steve Kowalik <[email protected]>
+
+- Update to 4.3.0:
+  * Added support for the Python 3.12 ``walk_up`` keyword argument in
+    ``anyio.Path.relative_to()``
+  * Fixed passing ``total_tokens`` to ``anyio.CapacityLimiter()`` as a
+    keyword argument not working on the ``trio`` backend
+  * Fixed ``Process.aclose()`` not performing the minimum level of
+    necessary cleanup when cancelled
+  * Fixed ``Process.stdin.aclose()``, ``Process.stdout.aclose()``, and
+    ``Process.stderr.aclose()``
+- Add exceptiongroup to {Build,}Requires.
+
+-------------------------------------------------------------------

Old:
----
  anyio-4.2.0.tar.gz

New:
----
  anyio-4.3.0.tar.gz

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

Other differences:
------------------
++++++ python-anyio.spec ++++++
--- /var/tmp/diff_new_pack.AJJVke/_old  2024-03-14 17:42:36.027967776 +0100
+++ /var/tmp/diff_new_pack.AJJVke/_new  2024-03-14 17:42:36.031967923 +0100
@@ -18,14 +18,14 @@
 
 %{?sle15_python_module_pythons}
 Name:           python-anyio
-Version:        4.2.0
+Version:        4.3.0
 Release:        0
 Summary:        High level compatibility layer for asynchronous event loop 
implementations
 License:        MIT
 URL:            https://github.com/agronholm/anyio
 Source:         
https://files.pythonhosted.org/packages/source/a/anyio/anyio-%{version}.tar.gz
-BuildRequires:  %{python_module contextlib2 if %python-base < 3.7}
-BuildRequires:  %{python_module dataclasses if %python-base < 3.7}
+BuildRequires:  %{python_module base >= 3.8}
+BuildRequires:  %{python_module exceptiongroup}
 BuildRequires:  %{python_module idna >= 2.8}
 BuildRequires:  %{python_module pip}
 BuildRequires:  %{python_module psutil >= 5.9}
@@ -37,7 +37,6 @@
 BuildRequires:  python-rpm-macros >= 20210127.3a18043
 # SECTION test requirements
 BuildRequires:  %{python_module hypothesis >= 4.0}
-BuildRequires:  %{python_module mock >= 4.0 if %python-base < 3.8}
 BuildRequires:  %{python_module pytest >= 7.0}
 BuildRequires:  %{python_module pytest-mock >= 3.6.1}
 BuildRequires:  %{python_module trio >= 0.23}
@@ -46,10 +45,9 @@
 BuildRequires:  fdupes
 Requires:       python-idna >= 2.8
 Requires:       python-sniffio >= 1.1
-Requires:       (python-typing_extensions if python-base < 3.11)
-%if 0%{?python_version_nodots} < 37
-Requires:       python-contextvars
-Requires:       python-dataclasses
+%if 0%{?python_version_nodots} < 311
+Requires:       python-exceptiongroup
+Requires:       python-typing_extensions
 %endif
 Suggests:       python-trio >= 0.23
 BuildArch:      noarch
@@ -95,5 +93,5 @@
 %doc README.rst
 %license LICENSE
 %{python_sitelib}/anyio
-%{python_sitelib}/anyio-%{version}*-info
+%{python_sitelib}/anyio-%{version}.dist-info
 

++++++ anyio-4.2.0.tar.gz -> anyio-4.3.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/anyio-4.2.0/.github/workflows/publish.yml 
new/anyio-4.3.0/.github/workflows/publish.yml
--- old/anyio-4.2.0/.github/workflows/publish.yml       2023-12-16 
18:06:12.000000000 +0100
+++ new/anyio-4.3.0/.github/workflows/publish.yml       2024-02-19 
09:35:33.000000000 +0100
@@ -24,7 +24,7 @@
     - name: Create packages
       run: python -m build
     - name: Archive packages
-      uses: actions/upload-artifact@v3
+      uses: actions/upload-artifact@v4
       with:
         name: dist
         path: dist
@@ -38,7 +38,7 @@
       id-token: write
     steps:
     - name: Retrieve packages
-      uses: actions/download-artifact@v3
+      uses: actions/download-artifact@v4
     - name: Upload packages
       uses: pypa/gh-action-pypi-publish@release/v1
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/anyio-4.2.0/.github/workflows/test.yml 
new/anyio-4.3.0/.github/workflows/test.yml
--- old/anyio-4.2.0/.github/workflows/test.yml  2023-12-16 18:06:12.000000000 
+0100
+++ new/anyio-4.3.0/.github/workflows/test.yml  2024-02-19 09:35:33.000000000 
+0100
@@ -18,7 +18,7 @@
     - uses: actions/checkout@v4
     - name: Get changed files by category
       id: changed-files
-      uses: tj-actions/changed-files@v37
+      uses: tj-actions/changed-files@v41
       with:
         files_yaml: |
           workflow:
@@ -66,11 +66,11 @@
         - os: macos-latest
           python-version: "3.8"
         - os: macos-latest
-          python-version: "3.11"
+          python-version: "3.12"
         - os: windows-latest
           python-version: "3.8"
         - os: windows-latest
-          python-version: "3.11"
+          python-version: "3.12"
     runs-on: ${{ matrix.os }}
     needs: changed-files
     if: |
@@ -92,12 +92,12 @@
     - name: Install dependencies
       run: pip install -e .[test]
     - name: Test with pytest
-      run: |
-        coverage run -m pytest -v
-        coverage xml
+      run: coverage run -m pytest -v
       timeout-minutes: 5
       env:
         PYTEST_DISABLE_PLUGIN_AUTOLOAD: 1
+    - name: Generate coverage report
+      run: coverage xml
     - name: Upload Coverage
       uses: coverallsapp/github-action@v2
       with:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/anyio-4.2.0/.pre-commit-config.yaml 
new/anyio-4.3.0/.pre-commit-config.yaml
--- old/anyio-4.2.0/.pre-commit-config.yaml     2023-12-16 18:06:12.000000000 
+0100
+++ new/anyio-4.3.0/.pre-commit-config.yaml     2024-02-19 09:35:33.000000000 
+0100
@@ -16,14 +16,14 @@
       - id: trailing-whitespace
 
   - repo: https://github.com/astral-sh/ruff-pre-commit
-    rev: v0.1.7
+    rev: v0.2.1
     hooks:
       - id: ruff
         args: [--fix, --show-fixes]
       - id: ruff-format
 
   - repo: https://github.com/pre-commit/mirrors-mypy
-    rev: v1.7.1
+    rev: v1.8.0
     hooks:
       - id: mypy
         additional_dependencies:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/anyio-4.2.0/PKG-INFO new/anyio-4.3.0/PKG-INFO
--- old/anyio-4.2.0/PKG-INFO    2023-12-16 18:06:20.394697200 +0100
+++ new/anyio-4.3.0/PKG-INFO    2024-02-19 09:35:45.028421400 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: anyio
-Version: 4.2.0
+Version: 4.3.0
 Summary: High level compatibility layer for multiple asynchronous event loop 
implementations
 Author-email: Alex Grönholm <[email protected]>
 License: MIT
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/anyio-4.2.0/docs/typedattrs.rst 
new/anyio-4.3.0/docs/typedattrs.rst
--- old/anyio-4.2.0/docs/typedattrs.rst 2023-12-16 18:06:12.000000000 +0100
+++ new/anyio-4.3.0/docs/typedattrs.rst 2024-02-19 09:35:33.000000000 +0100
@@ -34,21 +34,24 @@
 By convention, typed attributes are stored together in a container class with 
other
 attributes of the same category::
 
-    from anyio import TypedAttribute, TypedAttributeSet
+    from anyio import TypedAttributeSet, typed_attribute
 
 
-    class MyTypedAttribute:
-        string_valued_attribute = TypedAttribute[str]()
-        some_float_attribute = TypedAttribute[float]()
+    class MyTypedAttribute(TypedAttributeSet):
+        string_valued_attribute: str = typed_attribute()
+        some_float_attribute: float = typed_attribute()
 
 To provide values for these attributes, implement the
 :meth:`~.TypedAttributeProvider.extra_attributes` property in your class::
 
+    from collections.abc import Callable, Mapping
+
     from anyio import TypedAttributeProvider
 
 
     class MyAttributeProvider(TypedAttributeProvider):
-        def extra_attributes():
+        @property
+        def extra_attributes() -> Mapping[Any, Callable[[], Any]]:
             return {
                 MyTypedAttribute.string_valued_attribute: lambda: 'my 
attribute value',
                 MyTypedAttribute.some_float_attribute: lambda: 6.492
@@ -58,7 +61,8 @@
 attributes in the return value::
 
     class AnotherAttributeProvider(MyAttributeProvider):
-        def extra_attributes():
+        @property
+        def extra_attributes() -> Mapping[Any, Callable[[], Any]]:
             return {
                 **super().extra_attributes,
                 MyTypedAttribute.string_valued_attribute: lambda: 'overridden 
attribute value'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/anyio-4.2.0/docs/versionhistory.rst 
new/anyio-4.3.0/docs/versionhistory.rst
--- old/anyio-4.2.0/docs/versionhistory.rst     2023-12-16 18:06:12.000000000 
+0100
+++ new/anyio-4.3.0/docs/versionhistory.rst     2024-02-19 09:35:33.000000000 
+0100
@@ -3,6 +3,27 @@
 
 This library adheres to `Semantic Versioning 2.0 <http://semver.org/>`_.
 
+**4.3.0**
+
+- Added support for the Python 3.12 ``walk_up`` keyword argument in
+  ``anyio.Path.relative_to()`` (PR by Colin Taylor)
+- Fixed passing ``total_tokens`` to ``anyio.CapacityLimiter()`` as a keyword 
argument
+  not working on the ``trio`` backend
+  (`#515 <https://github.com/agronholm/anyio/issues/515>`_)
+- Fixed ``Process.aclose()`` not performing the minimum level of necessary 
cleanup when
+  cancelled. Previously:
+
+  - Cancellation of ``Process.aclose()`` could leak an orphan process
+  - Cancellation of ``run_process()`` could very briefly leak an orphan 
process.
+  - Cancellation of ``Process.aclose()`` or ``run_process()`` on Trio could 
leave
+    standard streams unclosed
+
+  (PR by Ganden Schaffner)
+- Fixed ``Process.stdin.aclose()``, ``Process.stdout.aclose()``, and
+  ``Process.stderr.aclose()`` not including a checkpoint on asyncio (PR by 
Ganden
+  Schaffner)
+- Fixed documentation on how to provide your own typed attributes
+
 **4.2.0**
 
 - Add support for ``byte``-based paths in ``connect_unix``, 
``create_unix_listeners``,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/anyio-4.2.0/src/anyio/_backends/_asyncio.py 
new/anyio-4.3.0/src/anyio/_backends/_asyncio.py
--- old/anyio-4.2.0/src/anyio/_backends/_asyncio.py     2023-12-16 
18:06:12.000000000 +0100
+++ new/anyio-4.3.0/src/anyio/_backends/_asyncio.py     2024-02-19 
09:35:33.000000000 +0100
@@ -918,6 +918,7 @@
 
     async def aclose(self) -> None:
         self._stream.feed_eof()
+        await AsyncIOBackend.checkpoint()
 
 
 @dataclass(eq=False)
@@ -930,6 +931,7 @@
 
     async def aclose(self) -> None:
         self._stream.close()
+        await AsyncIOBackend.checkpoint()
 
 
 @dataclass(eq=False)
@@ -940,14 +942,22 @@
     _stderr: StreamReaderWrapper | None
 
     async def aclose(self) -> None:
-        if self._stdin:
-            await self._stdin.aclose()
-        if self._stdout:
-            await self._stdout.aclose()
-        if self._stderr:
-            await self._stderr.aclose()
+        with CancelScope(shield=True):
+            if self._stdin:
+                await self._stdin.aclose()
+            if self._stdout:
+                await self._stdout.aclose()
+            if self._stderr:
+                await self._stderr.aclose()
+
+        try:
+            await self.wait()
+        except BaseException:
+            self.kill()
+            with CancelScope(shield=True):
+                await self.wait()
 
-        await self.wait()
+            raise
 
     async def wait(self) -> int:
         return await self._process.wait()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/anyio-4.2.0/src/anyio/_backends/_trio.py 
new/anyio-4.3.0/src/anyio/_backends/_trio.py
--- old/anyio-4.2.0/src/anyio/_backends/_trio.py        2023-12-16 
18:06:12.000000000 +0100
+++ new/anyio-4.3.0/src/anyio/_backends/_trio.py        2024-02-19 
09:35:33.000000000 +0100
@@ -283,14 +283,21 @@
     _stderr: abc.ByteReceiveStream | None
 
     async def aclose(self) -> None:
-        if self._stdin:
-            await self._stdin.aclose()
-        if self._stdout:
-            await self._stdout.aclose()
-        if self._stderr:
-            await self._stderr.aclose()
-
-        await self.wait()
+        with CancelScope(shield=True):
+            if self._stdin:
+                await self._stdin.aclose()
+            if self._stdout:
+                await self._stdout.aclose()
+            if self._stderr:
+                await self._stderr.aclose()
+
+        try:
+            await self.wait()
+        except BaseException:
+            self.kill()
+            with CancelScope(shield=True):
+                await self.wait()
+            raise
 
     async def wait(self) -> int:
         return await self._process.wait()
@@ -631,14 +638,24 @@
 
 class CapacityLimiter(BaseCapacityLimiter):
     def __new__(
-        cls, *args: Any, original: trio.CapacityLimiter | None = None
+        cls,
+        total_tokens: float | None = None,
+        *,
+        original: trio.CapacityLimiter | None = None,
     ) -> CapacityLimiter:
         return object.__new__(cls)
 
     def __init__(
-        self, *args: Any, original: trio.CapacityLimiter | None = None
+        self,
+        total_tokens: float | None = None,
+        *,
+        original: trio.CapacityLimiter | None = None,
     ) -> None:
-        self.__original = original or trio.CapacityLimiter(*args)
+        if original is not None:
+            self.__original = original
+        else:
+            assert total_tokens is not None
+            self.__original = trio.CapacityLimiter(total_tokens)
 
     async def __aenter__(self) -> None:
         return await self.__original.__aenter__()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/anyio-4.2.0/src/anyio/_core/_fileio.py 
new/anyio-4.3.0/src/anyio/_core/_fileio.py
--- old/anyio-4.2.0/src/anyio/_core/_fileio.py  2023-12-16 18:06:12.000000000 
+0100
+++ new/anyio-4.3.0/src/anyio/_core/_fileio.py  2024-02-19 09:35:33.000000000 
+0100
@@ -514,8 +514,17 @@
     ) -> str:
         return await to_thread.run_sync(self._path.read_text, encoding, errors)
 
-    def relative_to(self, *other: str | PathLike[str]) -> Path:
-        return Path(self._path.relative_to(*other))
+    if sys.version_info >= (3, 12):
+
+        def relative_to(
+            self, *other: str | PathLike[str], walk_up: bool = False
+        ) -> Path:
+            return Path(self._path.relative_to(*other, walk_up=walk_up))
+
+    else:
+
+        def relative_to(self, *other: str | PathLike[str]) -> Path:
+            return Path(self._path.relative_to(*other))
 
     async def readlink(self) -> Path:
         target = await to_thread.run_sync(os.readlink, self._path)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/anyio-4.2.0/src/anyio/_core/_subprocesses.py 
new/anyio-4.3.0/src/anyio/_core/_subprocesses.py
--- old/anyio-4.2.0/src/anyio/_core/_subprocesses.py    2023-12-16 
18:06:12.000000000 +0100
+++ new/anyio-4.3.0/src/anyio/_core/_subprocesses.py    2024-02-19 
09:35:33.000000000 +0100
@@ -65,20 +65,18 @@
         start_new_session=start_new_session,
     ) as process:
         stream_contents: list[bytes | None] = [None, None]
-        try:
-            async with create_task_group() as tg:
-                if process.stdout:
-                    tg.start_soon(drain_stream, process.stdout, 0)
-                if process.stderr:
-                    tg.start_soon(drain_stream, process.stderr, 1)
-                if process.stdin and input:
-                    await process.stdin.send(input)
-                    await process.stdin.aclose()
+        async with create_task_group() as tg:
+            if process.stdout:
+                tg.start_soon(drain_stream, process.stdout, 0)
 
-                await process.wait()
-        except BaseException:
-            process.kill()
-            raise
+            if process.stderr:
+                tg.start_soon(drain_stream, process.stderr, 1)
+
+            if process.stdin and input:
+                await process.stdin.send(input)
+                await process.stdin.aclose()
+
+            await process.wait()
 
     output, errors = stream_contents
     if check and process.returncode != 0:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/anyio-4.2.0/src/anyio/_core/_synchronization.py 
new/anyio-4.3.0/src/anyio/_core/_synchronization.py
--- old/anyio-4.2.0/src/anyio/_core/_synchronization.py 2023-12-16 
18:06:12.000000000 +0100
+++ new/anyio-4.3.0/src/anyio/_core/_synchronization.py 2024-02-19 
09:35:33.000000000 +0100
@@ -623,6 +623,8 @@
 
     :param action: the action to guard against (visible in the 
:exc:`BusyResourceError`
         when triggered, e.g. "Another task is already {action} this resource")
+
+    .. versionadded:: 4.1
     """
 
     __slots__ = "action", "_guarded"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/anyio-4.2.0/src/anyio.egg-info/PKG-INFO 
new/anyio-4.3.0/src/anyio.egg-info/PKG-INFO
--- old/anyio-4.2.0/src/anyio.egg-info/PKG-INFO 2023-12-16 18:06:20.000000000 
+0100
+++ new/anyio-4.3.0/src/anyio.egg-info/PKG-INFO 2024-02-19 09:35:44.000000000 
+0100
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: anyio
-Version: 4.2.0
+Version: 4.3.0
 Summary: High level compatibility layer for multiple asynchronous event loop 
implementations
 Author-email: Alex Grönholm <[email protected]>
 License: MIT
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/anyio-4.2.0/tests/streams/test_tls.py 
new/anyio-4.3.0/tests/streams/test_tls.py
--- old/anyio-4.2.0/tests/streams/test_tls.py   2023-12-16 18:06:12.000000000 
+0100
+++ new/anyio-4.3.0/tests/streams/test_tls.py   2024-02-19 09:35:33.000000000 
+0100
@@ -2,7 +2,6 @@
 
 import socket
 import ssl
-import sys
 from contextlib import ExitStack
 from threading import Thread
 from typing import ContextManager, NoReturn
@@ -26,10 +25,6 @@
 from anyio.streams.tls import TLSAttribute, TLSListener, TLSStream
 
 pytestmark = pytest.mark.anyio
-skip_on_broken_openssl = pytest.mark.skipif(
-    (ssl.OPENSSL_VERSION_INFO[0] > 1 and sys.version_info < (3, 8)),
-    reason="Python 3.7 does not work with OpenSSL versions higher than 1.X",
-)
 
 
 class TestTLSStream:
@@ -193,7 +188,6 @@
             pytest.param(False, False, id="neither_standard"),
         ],
     )
-    @skip_on_broken_openssl
     async def test_ragged_eofs(
         self,
         server_context: ssl.SSLContext,
@@ -250,7 +244,6 @@
         else:
             assert server_exc is None
 
-    @skip_on_broken_openssl
     async def test_ragged_eof_on_receive(
         self, server_context: ssl.SSLContext, client_context: ssl.SSLContext
     ) -> None:
@@ -350,10 +343,7 @@
         ca.configure_trust(client_context)
         if force_tlsv12:
             expected_pattern = r"send_eof\(\) requires at least TLSv1.3"
-            if hasattr(ssl, "TLSVersion"):
-                client_context.maximum_version = ssl.TLSVersion.TLSv1_2
-            else:  # Python 3.6
-                client_context.options |= ssl.OP_NO_TLSv1_3
+            client_context.maximum_version = ssl.TLSVersion.TLSv1_2
         else:
             expected_pattern = (
                 r"send_eof\(\) has not yet been implemented for TLS streams"
@@ -397,7 +387,6 @@
 
 
 class TestTLSListener:
-    @skip_on_broken_openssl
     async def test_handshake_fail(
         self, server_context: ssl.SSLContext, caplog: pytest.LogCaptureFixture
     ) -> None:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/anyio-4.2.0/tests/test_fileio.py 
new/anyio-4.3.0/tests/test_fileio.py
--- old/anyio-4.2.0/tests/test_fileio.py        2023-12-16 18:06:12.000000000 
+0100
+++ new/anyio-4.3.0/tests/test_fileio.py        2024-02-19 09:35:33.000000000 
+0100
@@ -68,10 +68,15 @@
     def populated_tmpdir(self, tmp_path: pathlib.Path) -> pathlib.Path:
         tmp_path.joinpath("testfile").touch()
         tmp_path.joinpath("testfile2").touch()
+
         subdir = tmp_path / "subdir"
-        subdir.mkdir()
-        subdir.joinpath("dummyfile1.txt").touch()
-        subdir.joinpath("dummyfile2.txt").touch()
+        sibdir = tmp_path / "sibdir"
+
+        for subpath in (subdir, sibdir):
+            subpath.mkdir()
+            subpath.joinpath("dummyfile1.txt").touch()
+            subpath.joinpath("dummyfile2.txt").touch()
+
         return tmp_path
 
     async def test_properties(self) -> None:
@@ -297,19 +302,29 @@
         all_paths = []
         async for path in Path(populated_tmpdir).glob("**/*.txt"):
             assert isinstance(path, Path)
-            all_paths.append(path.name)
+            all_paths.append(path.relative_to(populated_tmpdir))
 
         all_paths.sort()
-        assert all_paths == ["dummyfile1.txt", "dummyfile2.txt"]
+        assert all_paths == [
+            Path("sibdir") / "dummyfile1.txt",
+            Path("sibdir") / "dummyfile2.txt",
+            Path("subdir") / "dummyfile1.txt",
+            Path("subdir") / "dummyfile2.txt",
+        ]
 
     async def test_rglob(self, populated_tmpdir: pathlib.Path) -> None:
         all_paths = []
         async for path in Path(populated_tmpdir).rglob("*.txt"):
             assert isinstance(path, Path)
-            all_paths.append(path.name)
+            all_paths.append(path.relative_to(populated_tmpdir))
 
         all_paths.sort()
-        assert all_paths == ["dummyfile1.txt", "dummyfile2.txt"]
+        assert all_paths == [
+            Path("sibdir") / "dummyfile1.txt",
+            Path("sibdir") / "dummyfile2.txt",
+            Path("subdir") / "dummyfile1.txt",
+            Path("subdir") / "dummyfile2.txt",
+        ]
 
     async def test_iterdir(self, populated_tmpdir: pathlib.Path) -> None:
         all_paths = []
@@ -318,7 +333,7 @@
             all_paths.append(path.name)
 
         all_paths.sort()
-        assert all_paths == ["subdir", "testfile", "testfile2"]
+        assert all_paths == ["sibdir", "subdir", "testfile", "testfile2"]
 
     def test_joinpath(self) -> None:
         path = Path("/foo").joinpath("bar")
@@ -421,10 +436,29 @@
         path.write_text("some text åäö", encoding="utf-8")
         assert await Path(path).read_text(encoding="utf-8") == "some text 
åäö"
 
-    async def test_relative_to(self, tmp_path: pathlib.Path) -> None:
+    async def test_relative_to_subpath(self, tmp_path: pathlib.Path) -> None:
         path = tmp_path / "subdir"
         assert path.relative_to(tmp_path) == Path("subdir")
 
+    @pytest.mark.skipif(
+        sys.version_info < (3, 12),
+        reason="Path.relative_to(walk_up=<bool>) is only available on Python 
3.12+",
+    )
+    async def test_relative_to_sibling(
+        self,
+        populated_tmpdir: pathlib.Path,
+        monkeypatch: pytest.MonkeyPatch,
+    ) -> None:
+        subdir = Path(populated_tmpdir / "subdir")
+        sibdir = Path(populated_tmpdir / "sibdir")
+
+        with pytest.raises(ValueError):
+            subdir.relative_to(sibdir, walk_up=False)
+
+        monkeypatch.chdir(sibdir)
+        relpath = subdir.relative_to(sibdir, walk_up=True) / "dummyfile1.txt"
+        assert os.access(relpath, os.R_OK)
+
     async def test_rename(self, tmp_path: pathlib.Path) -> None:
         path = tmp_path / "somefile"
         path.touch()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/anyio-4.2.0/tests/test_from_thread.py 
new/anyio-4.3.0/tests/test_from_thread.py
--- old/anyio-4.2.0/tests/test_from_thread.py   2023-12-16 18:06:12.000000000 
+0100
+++ new/anyio-4.3.0/tests/test_from_thread.py   2024-02-19 09:35:33.000000000 
+0100
@@ -220,9 +220,6 @@
         exc.match("This function can only be run from an AnyIO worker thread")
 
     async def test_contextvar_propagation(self, anyio_backend_name: str) -> 
None:
-        if anyio_backend_name == "asyncio" and sys.version_info < (3, 7):
-            pytest.skip("Asyncio does not propagate context before Python 3.7")
-
         var = ContextVar("var", default=1)
 
         async def async_func() -> int:
@@ -572,9 +569,6 @@
     def test_contextvar_propagation_sync(
         self, anyio_backend_name: str, anyio_backend_options: dict[str, Any]
     ) -> None:
-        if anyio_backend_name == "asyncio" and sys.version_info < (3, 7):
-            pytest.skip("Asyncio does not propagate context before Python 3.7")
-
         var = ContextVar("var", default=1)
         var.set(6)
         with start_blocking_portal(anyio_backend_name, anyio_backend_options) 
as portal:
@@ -585,9 +579,6 @@
     def test_contextvar_propagation_async(
         self, anyio_backend_name: str, anyio_backend_options: dict[str, Any]
     ) -> None:
-        if anyio_backend_name == "asyncio" and sys.version_info < (3, 7):
-            pytest.skip("Asyncio does not propagate context before Python 3.7")
-
         var = ContextVar("var", default=1)
         var.set(6)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/anyio-4.2.0/tests/test_sockets.py 
new/anyio-4.3.0/tests/test_sockets.py
--- old/anyio-4.2.0/tests/test_sockets.py       2023-12-16 18:06:12.000000000 
+0100
+++ new/anyio-4.3.0/tests/test_sockets.py       2024-02-19 09:35:33.000000000 
+0100
@@ -7,6 +7,7 @@
 import platform
 import socket
 import sys
+import tempfile
 import threading
 import time
 from contextlib import suppress
@@ -14,7 +15,7 @@
 from socket import AddressFamily
 from ssl import SSLContext, SSLError
 from threading import Thread
-from typing import Any, Iterable, Iterator, NoReturn, TypeVar, cast
+from typing import Any, Generator, Iterable, Iterator, NoReturn, TypeVar, cast
 
 import psutil
 import pytest
@@ -511,6 +512,7 @@
         assert not caplog.text
 
 
[email protected]
 class TestTCPListener:
     async def test_extra_attributes(self, family: AnyIPAddressFamily) -> None:
         async with await create_tcp_listener(
@@ -707,8 +709,11 @@
 )
 class TestUNIXStream:
     @pytest.fixture
-    def socket_path(self, tmp_path_factory: TempPathFactory) -> Path:
-        return tmp_path_factory.mktemp("unix").joinpath("socket")
+    def socket_path(self) -> Generator[Path, None, None]:
+        # Use stdlib tempdir generation
+        # Fixes `OSError: AF_UNIX path too long` from pytest generated 
temp_path
+        with tempfile.TemporaryDirectory() as path:
+            yield Path(path) / "socket"
 
     @pytest.fixture(params=[False, True], ids=["str", "path"])
     def socket_path_or_str(self, request: SubRequest, socket_path: Path) -> 
Path | str:
@@ -1026,8 +1031,11 @@
 )
 class TestUNIXListener:
     @pytest.fixture
-    def socket_path(self, tmp_path_factory: TempPathFactory) -> Path:
-        return tmp_path_factory.mktemp("unix").joinpath("socket")
+    def socket_path(self) -> Generator[Path, None, None]:
+        # Use stdlib tempdir generation
+        # Fixes `OSError: AF_UNIX path too long` from pytest generated 
temp_path
+        with tempfile.TemporaryDirectory() as path:
+            yield Path(path) / "socket"
 
     @pytest.fixture(params=[False, True], ids=["str", "path"])
     def socket_path_or_str(self, request: SubRequest, socket_path: Path) -> 
Path | str:
@@ -1140,37 +1148,40 @@
 
     client_addresses: list[str | IPSockAddrType] = []
     listeners: list[Listener] = [await 
create_tcp_listener(local_host="localhost")]
-    if sys.platform != "win32":
-        socket_path = tmp_path_factory.mktemp("unix").joinpath("socket")
-        listeners.append(await create_unix_listener(socket_path))
-
-    expected_addresses: list[str | IPSockAddrType] = []
-    async with MultiListener(listeners) as multi_listener:
-        async with create_task_group() as tg:
-            tg.start_soon(multi_listener.serve, handle)
-            for listener in multi_listener.listeners:
-                event = Event()
-                local_address = listener.extra(SocketAttribute.local_address)
-                if (
-                    sys.platform != "win32"
-                    and listener.extra(SocketAttribute.family)
-                    == socket.AddressFamily.AF_UNIX
-                ):
-                    assert isinstance(local_address, str)
-                    stream: SocketStream = await connect_unix(local_address)
-                else:
-                    assert isinstance(local_address, tuple)
-                    stream = await connect_tcp(*local_address)
+    with tempfile.TemporaryDirectory() as path:
+        if sys.platform != "win32":
+            listeners.append(await create_unix_listener(Path(path) / "socket"))
 
-                
expected_addresses.append(stream.extra(SocketAttribute.local_address))
-                await event.wait()
-                await stream.aclose()
+        expected_addresses: list[str | IPSockAddrType] = []
+        async with MultiListener(listeners) as multi_listener:
+            async with create_task_group() as tg:
+                tg.start_soon(multi_listener.serve, handle)
+                for listener in multi_listener.listeners:
+                    event = Event()
+                    local_address = 
listener.extra(SocketAttribute.local_address)
+                    if (
+                        sys.platform != "win32"
+                        and listener.extra(SocketAttribute.family)
+                        == socket.AddressFamily.AF_UNIX
+                    ):
+                        assert isinstance(local_address, str)
+                        stream: SocketStream = await 
connect_unix(local_address)
+                    else:
+                        assert isinstance(local_address, tuple)
+                        stream = await connect_tcp(*local_address)
 
-            tg.cancel_scope.cancel()
+                    expected_addresses.append(
+                        stream.extra(SocketAttribute.local_address)
+                    )
+                    await event.wait()
+                    await stream.aclose()
+
+                tg.cancel_scope.cancel()
 
-    assert client_addresses == expected_addresses
+        assert client_addresses == expected_addresses
 
 
[email protected]
 @pytest.mark.usefixtures("check_asyncio_bug")
 class TestUDPSocket:
     async def test_extra_attributes(self, family: AnyIPAddressFamily) -> None:
@@ -1296,6 +1307,7 @@
             assert local_address[1] > 0
 
 
[email protected]
 @pytest.mark.usefixtures("check_asyncio_bug")
 class TestConnectedUDPSocket:
     async def test_extra_attributes(self, family: AnyIPAddressFamily) -> None:
@@ -1423,16 +1435,22 @@
 )
 class TestUNIXDatagramSocket:
     @pytest.fixture
-    def socket_path(self, tmp_path_factory: TempPathFactory) -> Path:
-        return tmp_path_factory.mktemp("unix").joinpath("socket")
+    def socket_path(self) -> Generator[Path, None, None]:
+        # Use stdlib tempdir generation
+        # Fixes `OSError: AF_UNIX path too long` from pytest generated 
temp_path
+        with tempfile.TemporaryDirectory() as path:
+            yield Path(path) / "socket"
 
     @pytest.fixture(params=[False, True], ids=["str", "path"])
     def socket_path_or_str(self, request: SubRequest, socket_path: Path) -> 
Path | str:
         return socket_path if request.param else str(socket_path)
 
     @pytest.fixture
-    def peer_socket_path(self, tmp_path_factory: TempPathFactory) -> Path:
-        return tmp_path_factory.mktemp("unix").joinpath("peer_socket")
+    def peer_socket_path(self) -> Generator[Path, None, None]:
+        # Use stdlib tempdir generation
+        # Fixes `OSError: AF_UNIX path too long` from pytest generated 
temp_path
+        with tempfile.TemporaryDirectory() as path:
+            yield Path(path) / "peer_socket"
 
     async def test_extra_attributes(self, socket_path: Path) -> None:
         async with await create_unix_datagram_socket(local_path=socket_path) 
as unix_dg:
@@ -1545,16 +1563,22 @@
 )
 class TestConnectedUNIXDatagramSocket:
     @pytest.fixture
-    def socket_path(self, tmp_path_factory: TempPathFactory) -> Path:
-        return tmp_path_factory.mktemp("unix").joinpath("socket")
+    def socket_path(self) -> Generator[Path, None, None]:
+        # Use stdlib tempdir generation
+        # Fixes `OSError: AF_UNIX path too long` from pytest generated 
temp_path
+        with tempfile.TemporaryDirectory() as path:
+            yield Path(path) / "socket"
 
     @pytest.fixture(params=[False, True], ids=["str", "path"])
     def socket_path_or_str(self, request: SubRequest, socket_path: Path) -> 
Path | str:
         return socket_path if request.param else str(socket_path)
 
     @pytest.fixture
-    def peer_socket_path(self, tmp_path_factory: TempPathFactory) -> Path:
-        return tmp_path_factory.mktemp("unix").joinpath("peer_socket")
+    def peer_socket_path(self) -> Generator[Path, None, None]:
+        # Use stdlib tempdir generation
+        # Fixes `OSError: AF_UNIX path too long` from pytest generated 
temp_path
+        with tempfile.TemporaryDirectory() as path:
+            yield Path(path) / "peer_socket"
 
     @pytest.fixture(params=[False, True], ids=["peer_str", "peer_path"])
     def peer_socket_path_or_str(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/anyio-4.2.0/tests/test_subprocesses.py 
new/anyio-4.3.0/tests/test_subprocesses.py
--- old/anyio-4.2.0/tests/test_subprocesses.py  2023-12-16 18:06:12.000000000 
+0100
+++ new/anyio-4.3.0/tests/test_subprocesses.py  2024-02-19 09:35:33.000000000 
+0100
@@ -8,23 +8,14 @@
 from textwrap import dedent
 
 import pytest
+from _pytest.fixtures import FixtureRequest
 
-from anyio import open_process, run_process
+from anyio import CancelScope, ClosedResourceError, open_process, run_process
 from anyio.streams.buffered import BufferedByteReceiveStream
 
 pytestmark = pytest.mark.anyio
 
 
[email protected](autouse=True)
-def check_compatibility(anyio_backend_name: str) -> None:
-    if anyio_backend_name == "asyncio":
-        if platform.system() == "Windows" and sys.version_info < (3, 8):
-            pytest.skip(
-                "Python < 3.8 uses SelectorEventLoop by default and it does 
not "
-                "support subprocesses"
-            )
-
-
 @pytest.mark.parametrize(
     "shell, command",
     [
@@ -176,3 +167,61 @@
     out, err = capfd.readouterr()
     assert out == "stdout-text" + os.linesep
     assert err == "stderr-text" + os.linesep
+
+
+async def test_process_aexit_cancellation_doesnt_orphan_process() -> None:
+    """
+    Regression test for #669.
+
+    Ensures that open_process.__aexit__() doesn't leave behind an orphan 
process when
+    cancelled.
+
+    """
+    with CancelScope() as scope:
+        async with await open_process(
+            [sys.executable, "-c", "import time; time.sleep(1)"]
+        ) as process:
+            scope.cancel()
+
+    assert process.returncode is not None
+    assert process.returncode != 0
+
+
+async def test_process_aexit_cancellation_closes_standard_streams(
+    request: FixtureRequest,
+    anyio_backend_name: str,
+) -> None:
+    """
+    Regression test for #669.
+
+    Ensures that open_process.__aexit__() closes standard streams when 
cancelled. Also
+    ensures that process.std{in.send,{out,err}.receive}() raise 
ClosedResourceError on a
+    closed stream.
+
+    """
+    if anyio_backend_name == "asyncio":
+        # Avoid pytest.xfail here due to 
https://github.com/pytest-dev/pytest/issues/9027
+        request.node.add_marker(
+            pytest.mark.xfail(reason="#671 needs to be resolved first")
+        )
+
+    with CancelScope() as scope:
+        async with await open_process(
+            [sys.executable, "-c", "import time; time.sleep(1)"]
+        ) as process:
+            scope.cancel()
+
+    assert process.stdin is not None
+
+    with pytest.raises(ClosedResourceError):
+        await process.stdin.send(b"foo")
+
+    assert process.stdout is not None
+
+    with pytest.raises(ClosedResourceError):
+        await process.stdout.receive(1)
+
+    assert process.stderr is not None
+
+    with pytest.raises(ClosedResourceError):
+        await process.stderr.receive(1)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/anyio-4.2.0/tests/test_synchronization.py 
new/anyio-4.3.0/tests/test_synchronization.py
--- old/anyio-4.2.0/tests/test_synchronization.py       2023-12-16 
18:06:12.000000000 +0100
+++ new/anyio-4.3.0/tests/test_synchronization.py       2024-02-19 
09:35:33.000000000 +0100
@@ -689,3 +689,8 @@
             backend=anyio_backend_name,
             backend_options=anyio_backend_options,
         )
+
+    async def test_total_tokens_as_kwarg(self) -> None:
+        # Regression test for #515
+        limiter = CapacityLimiter(total_tokens=1)
+        assert limiter.total_tokens == 1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/anyio-4.2.0/tests/test_taskgroups.py 
new/anyio-4.3.0/tests/test_taskgroups.py
--- old/anyio-4.2.0/tests/test_taskgroups.py    2023-12-16 18:06:12.000000000 
+0100
+++ new/anyio-4.3.0/tests/test_taskgroups.py    2024-02-19 09:35:33.000000000 
+0100
@@ -185,6 +185,9 @@
     assert not finished
 
 
[email protected](
+    sys.version_info < (3, 9), reason="Requires a way to detect cancellation 
source"
+)
 @pytest.mark.parametrize("anyio_backend", ["asyncio"])
 async def test_start_native_host_cancelled() -> None:
     started = finished = False
@@ -199,9 +202,6 @@
         async with create_task_group() as tg:
             await tg.start(taskfunc)
 
-    if sys.version_info < (3, 9):
-        pytest.xfail("Requires a way to detect cancellation source")
-
     task = asyncio.get_running_loop().create_task(start_another())
     await wait_all_tasks_blocked()
     task.cancel()
@@ -530,7 +530,7 @@
     reason="There is currently no way to tell if cancellation happened due to 
timeout "
     "explicitly if the deadline has been exceeded"
 )
-async def test_fail_after_scope_camcelled_before_timeout() -> None:
+async def test_fail_after_scope_cancelled_before_timeout() -> None:
     with fail_after(0.1) as scope:
         scope.cancel()
         time.sleep(0.11)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/anyio-4.2.0/tests/test_to_process.py 
new/anyio-4.3.0/tests/test_to_process.py
--- old/anyio-4.2.0/tests/test_to_process.py    2023-12-16 18:06:12.000000000 
+0100
+++ new/anyio-4.3.0/tests/test_to_process.py    2024-02-19 09:35:33.000000000 
+0100
@@ -1,7 +1,6 @@
 from __future__ import annotations
 
 import os
-import platform
 import sys
 import time
 from functools import partial
@@ -21,16 +20,6 @@
 pytestmark = pytest.mark.anyio
 
 
[email protected](autouse=True)
-def check_compatibility(anyio_backend_name: str) -> None:
-    if anyio_backend_name == "asyncio":
-        if platform.system() == "Windows" and sys.version_info < (3, 8):
-            pytest.skip(
-                "Python < 3.8 uses SelectorEventLoop by default and it does 
not "
-                "support subprocesses"
-            )
-
-
 async def test_run_sync_in_process_pool() -> None:
     """
     Test that the function runs in a different process, and the same process 
in both

Reply via email to