diff -pruN 0.25.1-1/.github/workflows/main.yml 1.1.0-2/.github/workflows/main.yml
--- 0.25.1-1/.github/workflows/main.yml	2025-01-02 04:58:42.000000000 +0000
+++ 1.1.0-2/.github/workflows/main.yml	2025-07-16 03:50:17.000000000 +0000
@@ -10,6 +10,8 @@ on:
   merge_group:
   workflow_dispatch:
 
+permissions: {}
+
 env:
   PYTHON_LATEST: 3.13
 
@@ -24,6 +26,7 @@ jobs:
     - uses: actions/checkout@v4
       with:
         fetch-depth: 0
+        persist-credentials: false
     - uses: actions/setup-python@v5
       with:
         python-version: ${{ env.PYTHON_LATEST }}
@@ -58,20 +61,26 @@ jobs:
   test:
     name: ${{ matrix.os }} - Python ${{ matrix.python-version }}
     runs-on: ${{ matrix.os }}-latest
-
+    continue-on-error: ${{ !matrix.required }}
     strategy:
       matrix:
         os: [ubuntu, windows]
         python-version: ['3.9', '3.10', '3.11', '3.12', '3.13']
+        required: [true]
+        include:
+        - os: ubuntu
+          python-version: 3.14-dev
+          required: false
+        - os: windows
+          python-version: 3.14-dev
+          required: false
+
 
     steps:
     - uses: actions/checkout@v4
-    - uses: actions/setup-python@v5
-      if: "!endsWith(matrix.python-version, '-dev')"
       with:
-        python-version: ${{ matrix.python-version }}
-    - uses: deadsnakes/action@v3.2.0
-      if: endsWith(matrix.python-version, '-dev')
+        persist-credentials: false
+    - uses: actions/setup-python@v5
       with:
         python-version: ${{ matrix.python-version }}
     - name: Install dependencies
@@ -91,6 +100,12 @@ jobs:
         path: coverage/coverage.*
         if-no-files-found: error
 
+  lint-github-actions:
+    name: Lint GitHub Actions
+    permissions:
+      security-events: write
+    uses: zizmorcore/workflow/.github/workflows/reusable-zizmor.yml@3bb5e95068d0f44b6d2f3f7e91379bed1d2f96a8
+
   check:
     name: Check
     if: always()
@@ -98,10 +113,12 @@ jobs:
     runs-on: ubuntu-latest
     steps:
     - name: Decide whether the needed jobs succeeded or failed
-      uses: re-actors/alls-green@release/v1
+      uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe  # v1.2.2
       with:
         jobs: ${{ toJSON(needs) }}
     - uses: actions/checkout@v4
+      with:
+        persist-credentials: false
     - uses: actions/setup-python@v5
       with:
         python-version: ${{ env.PYTHON_LATEST }}
@@ -120,47 +137,103 @@ jobs:
         coverage combine
         coverage xml
     - name: Upload coverage report
-      uses: codecov/codecov-action@v5
+      uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24  # v5.4.3
       with:
         files: coverage.xml
         fail_ci_if_error: true
         token: ${{ secrets.CODECOV_TOKEN }}
 
-  deploy:
-    name: Deploy
-    environment: release
-        # Run only on pushing a tag
-    if: github.event_name == 'push' && contains(github.ref, 'refs/tags/')
+  create-github-release:
+    name: Create GitHub release
     needs: [lint, check]
     runs-on: ubuntu-latest
+    permissions:
+      contents: write
     steps:
+    - name: Checkout
+      uses: actions/checkout@v4
+      with:
+        fetch-depth: 0
+        persist-credentials: false
+    - name: Install Python
+      uses: actions/setup-python@v5
+    - name: Install towncrier
+      run: pip install towncrier==24.8.0
     - name: Install pandoc
       run: |
         sudo apt-get install -y pandoc
-    - name: Checkout
-      uses: actions/checkout@v4
+    - name: Install pytest-asyncio
+      run: pip install .
+    - name: Compile Release Notes Draft
+      if: ${{ !contains(github.ref, 'refs/tags/') }}
+      run: towncrier build --draft --version "${version}" > release-notes.rst
+      env:
+        version: ${{ needs.lint.outputs.version }}
+    - name: Extract release notes from Git tag
+      if: github.event_name == 'push' && contains(github.ref, 'refs/tags/')
+      run: |
+        set -e
+        git fetch --tags --force  # see https://github.com/actions/checkout/issues/290
+        git for-each-ref "${GITHUB_REF}" --format='%(contents)' > release-notes.rst
+        # Strip PGP signature from signed tags
+        sed -i "/-----BEGIN PGP SIGNATURE-----/,/-----END PGP SIGNATURE-----\n/d" release-notes.rst
+    - name: Convert Release Notes to Markdown
+      run: |
+        pandoc -s -o release-notes.md release-notes.rst
+    - name: Upload artifacts
+      uses: actions/upload-artifact@v4
+      with:
+        name: release-notes.md
+        path: release-notes.md
     - name: Download distributions
       uses: actions/download-artifact@v4
       with:
         name: dist
         path: dist
-    - name: Collected dists
-      run: |
-        tree dist
-    - name: Convert README.rst to Markdown
-      run: |
-        pandoc -s -o README.md README.rst
-    - name: PyPI upload
-      uses: pypa/gh-action-pypi-publish@v1.12.3
-      with:
-        attestations: true
-        packages-dir: dist
-        password: ${{ secrets.PYPI_API_TOKEN }}
-    - name: GitHub Release
-      uses: ncipollo/release-action@v1
+    - name: Create GitHub Release
+      if: github.event_name == 'push' && contains(github.ref, 'refs/tags/')
+      uses: ncipollo/release-action@bcfe5470707e8832e12347755757cec0eb3c22af  # v1.18.0
       with:
         name: pytest-asyncio ${{ needs.lint.outputs.version }}
         artifacts: dist/*
-        bodyFile: README.md
+        bodyFile: release-notes.md
         prerelease: ${{ needs.lint.outputs.prerelease }}
         token: ${{ secrets.GITHUB_TOKEN }}
+
+  publish-test-pypi:
+    name: Publish packages to test.pypi.org
+    if: github.event_name == 'push' && github.ref == 'refs/heads/main'
+    needs: [lint, check]
+    runs-on: ubuntu-latest
+    permissions:
+      id-token: write
+    steps:
+    - name: Download distributions
+      uses: actions/download-artifact@v4
+      with:
+        name: dist
+        path: dist
+    - name: Upload to test.pypi.org
+      uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc  # v1.12.4
+      with:
+        repository-url: https://test.pypi.org/legacy/
+
+  publish-pypi:
+    name: Publish packages to pypi.org
+    environment: release
+    if: github.event_name == 'push' && contains(github.ref, 'refs/tags/')
+    needs: [lint, check]
+    runs-on: ubuntu-latest
+    permissions:
+      id-token: write
+    steps:
+    - name: Download distributions
+      uses: actions/download-artifact@v4
+      with:
+        name: dist
+        path: dist
+    - name: Collected dists
+      run: |
+        tree dist
+    - name: PyPI upload
+      uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc  # v1.12.4
diff -pruN 0.25.1-1/.pre-commit-config.yaml 1.1.0-2/.pre-commit-config.yaml
--- 0.25.1-1/.pre-commit-config.yaml	2025-01-02 04:58:42.000000000 +0000
+++ 1.1.0-2/.pre-commit-config.yaml	2025-07-16 03:50:17.000000000 +0000
@@ -6,7 +6,7 @@ repos:
   - id: check-merge-conflict
     exclude: rst$
 - repo: https://github.com/astral-sh/ruff-pre-commit
-  rev: v0.8.4
+  rev: v0.12.3
   hooks:
   - id: ruff
     args: [--fix]
@@ -15,7 +15,7 @@ repos:
   hooks:
   - id: yesqa
 - repo: https://github.com/Zac-HD/shed
-  rev: 2024.10.1
+  rev: 2025.6.1
   hooks:
   - id: shed
     args:
@@ -42,7 +42,7 @@ repos:
   - id: check-yaml
   - id: debug-statements
 - repo: https://github.com/pre-commit/mirrors-mypy
-  rev: v1.14.0
+  rev: v1.16.1
   hooks:
   - id: mypy
     exclude: ^(docs|tests)/.*
@@ -53,7 +53,7 @@ repos:
   hooks:
   - id: python-use-type-annotations
 - repo: https://github.com/rhysd/actionlint
-  rev: v1.7.5
+  rev: v1.7.7
   hooks:
   - id: actionlint-docker
     args:
@@ -65,15 +65,19 @@ repos:
     - 'SC1004:'
     stages: [manual]
 - repo: https://github.com/sirosen/check-jsonschema
-  rev: 0.30.0
+  rev: 0.33.2
   hooks:
   - id: check-github-actions
 - repo: https://github.com/tox-dev/pyproject-fmt
-  rev: v2.5.0
+  rev: v2.6.0
   hooks:
   - id: pyproject-fmt
       # https://pyproject-fmt.readthedocs.io/en/latest/#calculating-max-supported-python-version
     additional_dependencies: [tox>=4.9]
+- repo: https://github.com/zizmorcore/zizmor-pre-commit
+  rev: v1.11.0
+  hooks:
+  - id: zizmor
 ci:
   skip:
   - actionlint-docker
diff -pruN 0.25.1-1/debian/changelog 1.1.0-2/debian/changelog
--- 0.25.1-1/debian/changelog	2025-01-03 19:57:36.000000000 +0000
+++ 1.1.0-2/debian/changelog	2025-09-16 12:02:45.000000000 +0000
@@ -1,3 +1,21 @@
+python-pytest-asyncio (1.1.0-2) unstable; urgency=medium
+
+  * Team upload.
+  * Bump python3-pytest build-dependency to >= 8.4.0, since tests fail with
+    8.3.5.
+
+ -- Colin Watson <cjwatson@debian.org>  Tue, 16 Sep 2025 13:02:45 +0100
+
+python-pytest-asyncio (1.1.0-1) unstable; urgency=medium
+
+  * Team upload.
+  * d/watch: Upgrade to v5; exclude pre-releases.
+  * New upstream release (closes: #1114323).
+  * tests: Ignore warning when running with installed pytest_asyncio.
+  * Remove a cdbs leftover from the packaging.
+
+ -- Colin Watson <cjwatson@debian.org>  Mon, 15 Sep 2025 00:23:08 +0100
+
 python-pytest-asyncio (0.25.1-1) unstable; urgency=medium
 
   * New upstream release.
diff -pruN 0.25.1-1/debian/control 1.1.0-2/debian/control
--- 0.25.1-1/debian/control	2024-10-02 15:32:58.000000000 +0000
+++ 1.1.0-2/debian/control	2025-09-16 12:01:37.000000000 +0000
@@ -12,7 +12,7 @@ Build-Depends:
  python3-flaky <!nocheck>,
  python3-hypothesis (>= 5.7.1) <!nocheck>,
  python3-mypy <!nocheck>,
- python3-pytest (>= 5.4.0) <!nocheck>,
+ python3-pytest (>= 8.4.0) <!nocheck>,
  python3-pytest-trio <!nocheck>,
  python3-setuptools,
  python3-setuptools-scm,
@@ -27,7 +27,6 @@ Package: python3-pytest-asyncio
 Architecture: all
 Depends:
  python3-async-generator,
- ${cdbs:Depends},
  ${misc:Depends},
  ${python3:Depends},
 Provides: ${python3:Provides}
diff -pruN 0.25.1-1/debian/patches/series 1.1.0-2/debian/patches/series
--- 0.25.1-1/debian/patches/series	1970-01-01 00:00:00.000000000 +0000
+++ 1.1.0-2/debian/patches/series	2025-09-14 23:23:36.000000000 +0000
@@ -0,0 +1 @@
+tests-installed-pytest-asyncio.patch
diff -pruN 0.25.1-1/debian/patches/tests-installed-pytest-asyncio.patch 1.1.0-2/debian/patches/tests-installed-pytest-asyncio.patch
--- 0.25.1-1/debian/patches/tests-installed-pytest-asyncio.patch	1970-01-01 00:00:00.000000000 +0000
+++ 1.1.0-2/debian/patches/tests-installed-pytest-asyncio.patch	2025-09-14 23:23:36.000000000 +0000
@@ -0,0 +1,61 @@
+From: Colin Watson <cjwatson@debian.org>
+Date: Wed, 10 Sep 2025 01:00:47 +0100
+Subject: tests: Ignore warning when running with installed pytest_asyncio
+
+This happens in autopkgtests.
+
+Forwarded: not-needed
+Last-Update: 2025-10-10
+---
+ tests/test_event_loop_fixture.py | 19 ++++++++++++++++---
+ 1 file changed, 16 insertions(+), 3 deletions(-)
+
+diff --git a/tests/test_event_loop_fixture.py b/tests/test_event_loop_fixture.py
+index 8b9ac63..2ed0872 100644
+--- a/tests/test_event_loop_fixture.py
++++ b/tests/test_event_loop_fixture.py
+@@ -5,6 +5,13 @@ from textwrap import dedent
+ from pytest import Pytester
+ 
+ 
++_ignore_installed_warning = (
++    "ignore"
++    ":Module already imported so cannot be rewritten; pytest_asyncio"
++    ":pytest.PytestAssertRewriteWarning"
++)
++
++
+ def test_event_loop_fixture_respects_event_loop_policy(pytester: Pytester):
+     pytester.makeconftest(
+         dedent(
+@@ -78,7 +85,9 @@ def test_event_loop_fixture_handles_unclosed_async_gen(
+             """
+         )
+     )
+-    result = pytester.runpytest_subprocess("--asyncio-mode=strict", "-W", "default")
++    result = pytester.runpytest_subprocess(
++        "--asyncio-mode=strict", "-W", "default", "-W", _ignore_installed_warning
++    )
+     result.assert_outcomes(passed=1, warnings=0)
+ 
+ 
+@@ -110,7 +119,9 @@ def test_closing_event_loop_in_sync_fixture_teardown_raises_warning(
+             """
+         )
+     )
+-    result = pytester.runpytest_subprocess("--asyncio-mode=strict")
++    result = pytester.runpytest_subprocess(
++        "--asyncio-mode=strict", "-W", _ignore_installed_warning
++    )
+     result.assert_outcomes(passed=1, warnings=1)
+     result.stdout.fnmatch_lines(
+         ["*An exception occurred during teardown of an asyncio.Runner*"]
+@@ -139,5 +150,7 @@ def test_event_loop_fixture_asyncgen_error(
+             """
+         )
+     )
+-    result = pytester.runpytest_subprocess("--asyncio-mode=strict", "-W", "default")
++    result = pytester.runpytest_subprocess(
++        "--asyncio-mode=strict", "-W", "default", "-W", _ignore_installed_warning
++    )
+     result.assert_outcomes(passed=1, warnings=1)
diff -pruN 0.25.1-1/debian/rules 1.1.0-2/debian/rules
--- 0.25.1-1/debian/rules	2024-10-02 15:32:59.000000000 +0000
+++ 1.1.0-2/debian/rules	2025-09-14 23:23:35.000000000 +0000
@@ -1,8 +1,4 @@
 #!/usr/bin/make -f
 
-PYBUILD_TEST_ARGS = --asyncio-mode=auto -k "not test_can_use_explicit_event_loop_fixture and not test_event_loop_fixture_finalizer_raises_warning_when_fixture_leaves_loop_unclosed and not test_event_loop_fixture_finalizer_raises_warning_when_test_leaves_loop_unclosed and not test_returns_false_for_unmarked_coroutine_item_in_strict_mode"
-
-export PYBUILD_TEST_ARGS
-
 %:
 	dh $@ --buildsystem=pybuild
diff -pruN 0.25.1-1/debian/watch 1.1.0-2/debian/watch
--- 0.25.1-1/debian/watch	2024-09-25 10:02:06.000000000 +0000
+++ 1.1.0-2/debian/watch	2025-09-09 23:21:15.000000000 +0000
@@ -1,8 +1,6 @@
-version=4
-# check: uscan --report
-# update: gbp import-orig --upstream-vcs-tag=vX.Y.Z --uscan
+Version: 5
 
-opts=\
-filenamemangle=s/.*?(@ANY_VERSION@@ARCHIVE_EXT@)/@PACKAGE@-$1/ \
-https://github.com/pytest-dev/pytest-asyncio/tags \
-.*?@ANY_VERSION@@ARCHIVE_EXT@
+Template: Github
+Owner: pytest-dev
+Project: pytest-asyncio
+Uversion-Mangle: s/(\d)([ab]\d*)$/$1~$2/
diff -pruN 0.25.1-1/dependencies/default/constraints.txt 1.1.0-2/dependencies/default/constraints.txt
--- 0.25.1-1/dependencies/default/constraints.txt	2025-01-02 04:58:42.000000000 +0000
+++ 1.1.0-2/dependencies/default/constraints.txt	2025-07-16 03:50:17.000000000 +0000
@@ -1,11 +1,11 @@
-attrs==24.3.0
-coverage==7.6.10
-exceptiongroup==1.2.2
-hypothesis==6.123.2
-iniconfig==2.0.0
-packaging==24.2
-pluggy==1.5.0
-pytest==8.3.4
+attrs==25.3.0
+coverage==7.9.2
+exceptiongroup==1.3.0
+hypothesis==6.135.29
+iniconfig==2.1.0
+packaging==25.0
+pluggy==1.6.0
+pytest==8.4.1
 sortedcontainers==2.4.0
 tomli==2.2.1
-typing_extensions==4.12.2
+typing_extensions==4.14.1
diff -pruN 0.25.1-1/dependencies/docs/constraints.txt 1.1.0-2/dependencies/docs/constraints.txt
--- 0.25.1-1/dependencies/docs/constraints.txt	2025-01-02 04:58:42.000000000 +0000
+++ 1.1.0-2/dependencies/docs/constraints.txt	2025-07-16 03:50:17.000000000 +0000
@@ -1,16 +1,16 @@
 alabaster==0.7.16
-Babel==2.16.0
-certifi==2024.12.14
-charset-normalizer==3.4.1
+Babel==2.17.0
+certifi==2025.7.14
+charset-normalizer==3.4.2
 docutils==0.21.2
 idna==3.10
 imagesize==1.4.1
-Jinja2==3.1.5
+Jinja2==3.1.6
 MarkupSafe==3.0.2
-packaging==24.2
-Pygments==2.18.0
-requests==2.32.3
-snowballstemmer==2.2.0
+packaging==25.0
+Pygments==2.19.2
+requests==2.32.4
+snowballstemmer==3.0.1
 Sphinx==8.0.2
 sphinx-rtd-theme==3.0.2
 sphinxcontrib-applehelp==2.0.0
@@ -20,4 +20,4 @@ sphinxcontrib-jquery==4.1
 sphinxcontrib-jsmath==1.0.1
 sphinxcontrib-qthelp==2.0.0
 sphinxcontrib-serializinghtml==2.0.0
-urllib3==2.3.0
+urllib3==2.5.0
diff -pruN 0.25.1-1/docs/concepts.rst 1.1.0-2/docs/concepts.rst
--- 0.25.1-1/docs/concepts.rst	2025-01-02 04:58:42.000000000 +0000
+++ 1.1.0-2/docs/concepts.rst	2025-07-16 03:50:17.000000000 +0000
@@ -47,8 +47,12 @@ Assigning neighboring tests to different
 Test discovery modes
 ====================
 
-Pytest-asyncio provides two modes for test discovery, *strict* and *auto*.
+Pytest-asyncio provides two modes for test discovery, *strict* and *auto*. This can be set through Pytest's ``--asyncio-mode`` command line flag, or through the configuration file:
 
+.. code-block:: toml
+
+    [tool.pytest.ini_options]
+    asyncio_mode = "auto" # or "strict"
 
 Strict mode
 -----------
diff -pruN 0.25.1-1/docs/how-to-guides/change_default_test_loop.rst 1.1.0-2/docs/how-to-guides/change_default_test_loop.rst
--- 0.25.1-1/docs/how-to-guides/change_default_test_loop.rst	1970-01-01 00:00:00.000000000 +0000
+++ 1.1.0-2/docs/how-to-guides/change_default_test_loop.rst	2025-07-16 03:50:17.000000000 +0000
@@ -0,0 +1,24 @@
+=======================================================
+How to change the default event loop scope of all tests
+=======================================================
+The :ref:`configuration/asyncio_default_test_loop_scope` configuration option sets the default event loop scope for asynchronous tests. The following code snippets configure all tests to run in a session-scoped loop by default:
+
+.. code-block:: ini
+    :caption: pytest.ini
+
+    [pytest]
+    asyncio_default_test_loop_scope = session
+
+.. code-block:: toml
+    :caption: pyproject.toml
+
+    [tool.pytest.ini_options]
+    asyncio_default_test_loop_scope = "session"
+
+.. code-block:: ini
+    :caption: setup.cfg
+
+    [tool:pytest]
+    asyncio_default_test_loop_scope = session
+
+Please refer to :ref:`configuration/asyncio_default_test_loop_scope` for other valid scopes.
diff -pruN 0.25.1-1/docs/how-to-guides/index.rst 1.1.0-2/docs/how-to-guides/index.rst
--- 0.25.1-1/docs/how-to-guides/index.rst	2025-01-02 04:58:42.000000000 +0000
+++ 1.1.0-2/docs/how-to-guides/index.rst	2025-07-16 03:50:17.000000000 +0000
@@ -9,10 +9,10 @@ How-To Guides
   migrate_from_0_23
   change_fixture_loop
   change_default_fixture_loop
+  change_default_test_loop
   run_class_tests_in_same_loop
   run_module_tests_in_same_loop
   run_package_tests_in_same_loop
-  run_session_tests_in_same_loop
   multiple_loops
   uvloop
   test_item_is_async
diff -pruN 0.25.1-1/docs/how-to-guides/multiple_loops_example.py 1.1.0-2/docs/how-to-guides/multiple_loops_example.py
--- 0.25.1-1/docs/how-to-guides/multiple_loops_example.py	2025-01-02 04:58:42.000000000 +0000
+++ 1.1.0-2/docs/how-to-guides/multiple_loops_example.py	2025-07-16 03:50:17.000000000 +0000
@@ -1,5 +1,9 @@
 import asyncio
-from asyncio import DefaultEventLoopPolicy
+import warnings
+
+with warnings.catch_warnings():
+    warnings.simplefilter("ignore", DeprecationWarning)
+    from asyncio import DefaultEventLoopPolicy
 
 import pytest
 
@@ -20,5 +24,6 @@ def event_loop_policy(request):
 
 
 @pytest.mark.asyncio
+@pytest.mark.filterwarnings("ignore::DeprecationWarning")
 async def test_uses_custom_event_loop_policy():
     assert isinstance(asyncio.get_event_loop_policy(), CustomEventLoopPolicy)
diff -pruN 0.25.1-1/docs/how-to-guides/run_session_tests_in_same_loop.rst 1.1.0-2/docs/how-to-guides/run_session_tests_in_same_loop.rst
--- 0.25.1-1/docs/how-to-guides/run_session_tests_in_same_loop.rst	2025-01-02 04:58:42.000000000 +0000
+++ 1.1.0-2/docs/how-to-guides/run_session_tests_in_same_loop.rst	1970-01-01 00:00:00.000000000 +0000
@@ -1,10 +0,0 @@
-==========================================================
-How to run all tests in the session in the same event loop
-==========================================================
-All tests can be run inside the same event loop by marking them with ``pytest.mark.asyncio(loop_scope="session")``.
-The easiest way to mark all tests is via a ``pytest_collection_modifyitems`` hook in the ``conftest.py`` at the root folder of your test suite.
-
-.. include:: session_scoped_loop_example.py
-    :code: python
-
-Note that this will also override *all* manually applied marks in *strict* mode.
diff -pruN 0.25.1-1/docs/how-to-guides/session_scoped_loop_example.py 1.1.0-2/docs/how-to-guides/session_scoped_loop_example.py
--- 0.25.1-1/docs/how-to-guides/session_scoped_loop_example.py	2025-01-02 04:58:42.000000000 +0000
+++ 1.1.0-2/docs/how-to-guides/session_scoped_loop_example.py	1970-01-01 00:00:00.000000000 +0000
@@ -1,10 +0,0 @@
-import pytest
-
-from pytest_asyncio import is_async_test
-
-
-def pytest_collection_modifyitems(items):
-    pytest_asyncio_tests = (item for item in items if is_async_test(item))
-    session_scope_marker = pytest.mark.asyncio(loop_scope="session")
-    for async_test in pytest_asyncio_tests:
-        async_test.add_marker(session_scope_marker, append=False)
diff -pruN 0.25.1-1/docs/how-to-guides/test_session_scoped_loop_example.py 1.1.0-2/docs/how-to-guides/test_session_scoped_loop_example.py
--- 0.25.1-1/docs/how-to-guides/test_session_scoped_loop_example.py	2025-01-02 04:58:42.000000000 +0000
+++ 1.1.0-2/docs/how-to-guides/test_session_scoped_loop_example.py	1970-01-01 00:00:00.000000000 +0000
@@ -1,63 +0,0 @@
-from pathlib import Path
-from textwrap import dedent
-
-from pytest import Pytester
-
-
-def test_session_scoped_loop_configuration_works_in_auto_mode(
-    pytester: Pytester,
-):
-    session_wide_mark_conftest = (
-        Path(__file__).parent / "session_scoped_loop_example.py"
-    )
-    pytester.makeconftest(session_wide_mark_conftest.read_text())
-    pytester.makepyfile(
-        dedent(
-            """\
-            import asyncio
-
-            session_loop = None
-
-            async def test_store_loop(request):
-                global session_loop
-                session_loop = asyncio.get_running_loop()
-
-            async def test_compare_loop(request):
-                global session_loop
-                assert asyncio.get_running_loop() is session_loop
-            """
-        )
-    )
-    result = pytester.runpytest_subprocess("--asyncio-mode=auto")
-    result.assert_outcomes(passed=2)
-
-
-def test_session_scoped_loop_configuration_works_in_strict_mode(
-    pytester: Pytester,
-):
-    session_wide_mark_conftest = (
-        Path(__file__).parent / "session_scoped_loop_example.py"
-    )
-    pytester.makeconftest(session_wide_mark_conftest.read_text())
-    pytester.makepyfile(
-        dedent(
-            """\
-            import asyncio
-            import pytest
-
-            session_loop = None
-
-            @pytest.mark.asyncio
-            async def test_store_loop(request):
-                global session_loop
-                session_loop = asyncio.get_running_loop()
-
-            @pytest.mark.asyncio
-            async def test_compare_loop(request):
-                global session_loop
-                assert asyncio.get_running_loop() is session_loop
-            """
-        )
-    )
-    result = pytester.runpytest_subprocess("--asyncio-mode=strict")
-    result.assert_outcomes(passed=2)
diff -pruN 0.25.1-1/docs/how-to-guides/uvloop.rst 1.1.0-2/docs/how-to-guides/uvloop.rst
--- 0.25.1-1/docs/how-to-guides/uvloop.rst	2025-01-02 04:58:42.000000000 +0000
+++ 1.1.0-2/docs/how-to-guides/uvloop.rst	2025-07-16 03:50:17.000000000 +0000
@@ -2,7 +2,7 @@
 How to test with uvloop
 =======================
 
-Redefinig the *event_loop_policy* fixture will parametrize all async tests. The following example causes all async tests to run multiple times, once for each event loop in the fixture parameters:
+Redefining the *event_loop_policy* fixture will parametrize all async tests. The following example causes all async tests to run multiple times, once for each event loop in the fixture parameters:
 Replace the default event loop policy in your *conftest.py:*
 
 .. code-block:: python
diff -pruN 0.25.1-1/docs/reference/changelog.rst 1.1.0-2/docs/reference/changelog.rst
--- 0.25.1-1/docs/reference/changelog.rst	2025-01-02 04:58:42.000000000 +0000
+++ 1.1.0-2/docs/reference/changelog.rst	2025-07-16 03:50:17.000000000 +0000
@@ -2,6 +2,91 @@
 Changelog
 =========
 
+All notable changes to this project will be documented in this file.
+
+The format is based on `Keep a Changelog <https://keepachangelog.com/en/1.1.0/>`__, and this project adheres to `Semantic Versioning <https://semver.org/spec/v2.0.0.html>`__.
+
+This project uses `towncrier <https://towncrier.readthedocs.io/>`__ for changlog management and the changes for the upcoming release can be found in https://github.com/pytest-dev/pytest-asyncio/tree/main/changelog.d/.
+
+.. towncrier release notes start
+
+`1.1.0 <https://github.com/pytest-dev/pytest-asyncio/tree/1.1.0>`_ - 2025-07-16
+===============================================================================
+
+Added
+-----
+
+- Propagation of ContextVars from async fixtures to other fixtures and tests on Python 3.10 and older (`#127 <https://github.com/pytest-dev/pytest-asyncio/issues/127>`_)
+- Cancellation of tasks when the `loop_scope` ends (`#200 <https://github.com/pytest-dev/pytest-asyncio/issues/200>`_)
+- Warning when the current event loop is closed by a test
+
+
+Fixed
+-----
+
+- Error about missing loop when calling functions requiring a loop in the `finally` clause of a task (`#878 <https://github.com/pytest-dev/pytest-asyncio/issues/878>`_)
+- An error that could cause duplicate warnings to be issued
+
+
+Notes for Downstream Packagers
+------------------------------
+
+- Added runtime dependency on `backports.asyncio.runner <https://pypi.org/project/backports.asyncio.runner/>`__ for use with Python 3.10 and older
+
+
+`1.0.0 <https://github.com/pytest-dev/pytest-asyncio/tree/1.0.0>`_ - 2025-05-26
+===============================================================================
+
+Removed
+-------
+
+- The deprecated *event_loop* fixture. (`#1106 <https://github.com/pytest-dev/pytest-asyncio/issues/1106>`_)
+
+
+Added
+-----
+
+- Prelimiary support for Python 3.14 (`#1025 <https://github.com/pytest-dev/pytest-asyncio/issues/1025>`_)
+
+
+Changed
+-------
+
+- Scoped event loops (e.g. module-scoped loops) are created once rather than per scope (e.g. per module). This reduces the number of fixtures and speeds up collection time, especially for large test suites. (`#1107 <https://github.com/pytest-dev/pytest-asyncio/issues/1107>`_)
+- The *loop_scope* argument to ``pytest.mark.asyncio`` no longer forces that a pytest Collector exists at the level of the specified scope. For example, a test function marked with ``pytest.mark.asyncio(loop_scope="class")`` no longer requires a class surrounding the test. This is consistent with the behavior of the *scope* argument to ``pytest_asyncio.fixture``. (`#1112 <https://github.com/pytest-dev/pytest-asyncio/issues/1112>`_)
+
+
+Fixed
+-----
+
+- An error caused when using pytest's `--setup-plan` option. (`#630 <https://github.com/pytest-dev/pytest-asyncio/issues/630>`_)
+- Unsuppressed import errors with pytest option ``--doctest-ignore-import-errors`` (`#797 <https://github.com/pytest-dev/pytest-asyncio/issues/797>`_)
+- A "fixture not found" error in connection with package-scoped loops (`#1052 <https://github.com/pytest-dev/pytest-asyncio/issues/1052>`_)
+
+
+Notes for Downstream Packagers
+------------------------------
+
+- Removed a test that had an ordering dependency on other tests. (`#1114 <https://github.com/pytest-dev/pytest-asyncio/issues/1114>`_)
+
+
+0.26.0 (2025-03-25)
+===================
+- Adds configuration option that sets default event loop scope for all tests `#793 <https://github.com/pytest-dev/pytest-asyncio/issues/793>`_
+- Improved type annotations for ``pytest_asyncio.fixture`` `#1045 <https://github.com/pytest-dev/pytest-asyncio/pull/1045>`_
+- Added ``typing-extensions`` as additional dependency for Python ``<3.10`` `#1045 <https://github.com/pytest-dev/pytest-asyncio/pull/1045>`_
+
+
+0.25.3 (2025-01-28)
+===================
+- Avoid errors in cleanup of async generators when event loop is already closed `#1040 <https://github.com/pytest-dev/pytest-asyncio/issues/1040>`_
+
+
+0.25.2 (2025-01-08)
+===================
+- Call ``loop.shutdown_asyncgens()`` before closing the event loop to ensure async generators are closed in the same manner as ``asyncio.run`` does `#1034 <https://github.com/pytest-dev/pytest-asyncio/pull/1034>`_
+
+
 0.25.1 (2025-01-02)
 ===================
 - Fixes an issue that caused a broken event loop when a function-scoped test was executed in between two tests with wider loop scope `#950 <https://github.com/pytest-dev/pytest-asyncio/issues/950>`_
@@ -17,7 +102,6 @@ Changelog
 - Propagates `contextvars` set in async fixtures to other fixtures and tests on Python 3.11 and above. `#1008 <https://github.com/pytest-dev/pytest-asyncio/pull/1008>`_
 
 
-
 0.24.0 (2024-08-22)
 ===================
 - BREAKING: Updated minimum supported pytest version to v8.2.0
diff -pruN 0.25.1-1/docs/reference/configuration.rst 1.1.0-2/docs/reference/configuration.rst
--- 0.25.1-1/docs/reference/configuration.rst	2025-01-02 04:58:42.000000000 +0000
+++ 1.1.0-2/docs/reference/configuration.rst	2025-07-16 03:50:17.000000000 +0000
@@ -8,6 +8,12 @@ asyncio_default_fixture_loop_scope
 ==================================
 Determines the default event loop scope of asynchronous fixtures. When this configuration option is unset, it defaults to the fixture scope. In future versions of pytest-asyncio, the value will default to ``function`` when unset. Possible values are: ``function``, ``class``, ``module``, ``package``, ``session``
 
+.. _configuration/asyncio_default_test_loop_scope:
+
+asyncio_default_test_loop_scope
+===============================
+Determines the default event loop scope of asynchronous tests. When this configuration option is unset, it default to function scope. Possible values are: ``function``, ``class``, ``module``, ``package``, ``session``
+
 asyncio_mode
 ============
 The pytest-asyncio mode can be set by the ``asyncio_mode`` configuration option in the `configuration file
diff -pruN 0.25.1-1/docs/reference/fixtures/event_loop_example.py 1.1.0-2/docs/reference/fixtures/event_loop_example.py
--- 0.25.1-1/docs/reference/fixtures/event_loop_example.py	2025-01-02 04:58:42.000000000 +0000
+++ 1.1.0-2/docs/reference/fixtures/event_loop_example.py	1970-01-01 00:00:00.000000000 +0000
@@ -1,5 +0,0 @@
-import asyncio
-
-
-def test_event_loop_fixture(event_loop):
-    event_loop.run_until_complete(asyncio.sleep(0))
diff -pruN 0.25.1-1/docs/reference/fixtures/event_loop_policy_example.py 1.1.0-2/docs/reference/fixtures/event_loop_policy_example.py
--- 0.25.1-1/docs/reference/fixtures/event_loop_policy_example.py	2025-01-02 04:58:42.000000000 +0000
+++ 1.1.0-2/docs/reference/fixtures/event_loop_policy_example.py	2025-07-16 03:50:17.000000000 +0000
@@ -1,9 +1,14 @@
 import asyncio
+import warnings
+
+with warnings.catch_warnings():
+    warnings.simplefilter("ignore", DeprecationWarning)
+    from asyncio import DefaultEventLoopPolicy
 
 import pytest
 
 
-class CustomEventLoopPolicy(asyncio.DefaultEventLoopPolicy):
+class CustomEventLoopPolicy(DefaultEventLoopPolicy):
     pass
 
 
@@ -13,5 +18,6 @@ def event_loop_policy(request):
 
 
 @pytest.mark.asyncio(loop_scope="module")
+@pytest.mark.filterwarnings("ignore::DeprecationWarning")
 async def test_uses_custom_event_loop_policy():
     assert isinstance(asyncio.get_event_loop_policy(), CustomEventLoopPolicy)
diff -pruN 0.25.1-1/docs/reference/fixtures/event_loop_policy_parametrized_example.py 1.1.0-2/docs/reference/fixtures/event_loop_policy_parametrized_example.py
--- 0.25.1-1/docs/reference/fixtures/event_loop_policy_parametrized_example.py	2025-01-02 04:58:42.000000000 +0000
+++ 1.1.0-2/docs/reference/fixtures/event_loop_policy_parametrized_example.py	2025-07-16 03:50:17.000000000 +0000
@@ -1,10 +1,14 @@
 import asyncio
-from asyncio import DefaultEventLoopPolicy
+import warnings
+
+with warnings.catch_warnings():
+    warnings.simplefilter("ignore", DeprecationWarning)
+    from asyncio import DefaultEventLoopPolicy
 
 import pytest
 
 
-class CustomEventLoopPolicy(asyncio.DefaultEventLoopPolicy):
+class CustomEventLoopPolicy(DefaultEventLoopPolicy):
     pass
 
 
@@ -19,5 +23,6 @@ def event_loop_policy(request):
 
 
 @pytest.mark.asyncio
+@pytest.mark.filterwarnings("ignore::DeprecationWarning")
 async def test_uses_custom_event_loop_policy():
     assert isinstance(asyncio.get_event_loop_policy(), DefaultEventLoopPolicy)
diff -pruN 0.25.1-1/docs/reference/fixtures/index.rst 1.1.0-2/docs/reference/fixtures/index.rst
--- 0.25.1-1/docs/reference/fixtures/index.rst	2025-01-02 04:58:42.000000000 +0000
+++ 1.1.0-2/docs/reference/fixtures/index.rst	2025-07-16 03:50:17.000000000 +0000
@@ -2,33 +2,6 @@
 Fixtures
 ========
 
-event_loop
-==========
-*This fixture is deprecated.*
-
-*If you want to request an asyncio event loop with a scope other than function
-scope, use the "loop_scope" argument to* :ref:`reference/markers/asyncio` *when marking the tests.
-If you want to return different types of event loops, use the* :ref:`reference/fixtures/event_loop_policy`
-*fixture.*
-
-Creates a new asyncio event loop based on the current event loop policy. The new loop
-is available as the return value of this fixture for synchronous functions, or via `asyncio.get_running_loop <https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.get_running_loop>`__ for asynchronous functions.
-The event loop is closed when the fixture scope ends.
-The fixture scope defaults to ``function`` scope.
-
-.. include:: event_loop_example.py
-    :code: python
-
-Note that, when using the ``event_loop`` fixture, you need to interact with the event loop using methods like ``event_loop.run_until_complete``. If you want to *await* code inside your test function, you need to write a coroutine and use it as a test function. The :ref:`asyncio <reference/markers/asyncio>` marker
-is used to mark coroutines that should be treated as test functions.
-
-If you need to change the type of the event loop, prefer setting a custom event loop policy over redefining the ``event_loop`` fixture.
-
-If the ``pytest.mark.asyncio`` decorator is applied to a test function, the ``event_loop``
-fixture will be requested automatically by the test function.
-
-.. _reference/fixtures/event_loop_policy:
-
 event_loop_policy
 =================
 Returns the event loop policy used to create asyncio event loops.
diff -pruN 0.25.1-1/docs/reference/markers/class_scoped_loop_custom_policies_strict_mode_example.py 1.1.0-2/docs/reference/markers/class_scoped_loop_custom_policies_strict_mode_example.py
--- 0.25.1-1/docs/reference/markers/class_scoped_loop_custom_policies_strict_mode_example.py	2025-01-02 04:58:42.000000000 +0000
+++ 1.1.0-2/docs/reference/markers/class_scoped_loop_custom_policies_strict_mode_example.py	2025-07-16 03:50:17.000000000 +0000
@@ -1,12 +1,16 @@
-import asyncio
+import warnings
+
+with warnings.catch_warnings():
+    warnings.simplefilter("ignore", DeprecationWarning)
+    from asyncio import DefaultEventLoopPolicy
 
 import pytest
 
 
 @pytest.fixture(
     params=[
-        asyncio.DefaultEventLoopPolicy(),
-        asyncio.DefaultEventLoopPolicy(),
+        DefaultEventLoopPolicy(),
+        DefaultEventLoopPolicy(),
     ]
 )
 def event_loop_policy(request):
diff -pruN 0.25.1-1/docs/reference/markers/index.rst 1.1.0-2/docs/reference/markers/index.rst
--- 0.25.1-1/docs/reference/markers/index.rst	2025-01-02 04:58:42.000000000 +0000
+++ 1.1.0-2/docs/reference/markers/index.rst	2025-07-16 03:50:17.000000000 +0000
@@ -21,21 +21,17 @@ The ``pytest.mark.asyncio`` marker can b
 
 By default, each test runs in it's own asyncio event loop.
 Multiple tests can share the same event loop by providing a *loop_scope* keyword argument to the *asyncio* mark.
-The supported scopes are *class,* and *module,* and *package*.
+The supported scopes are *function,* *class,* and *module,* *package,* and *session*.
 The following code example provides a shared event loop for all tests in `TestClassScopedLoop`:
 
 .. include:: class_scoped_loop_strict_mode_example.py
     :code: python
 
-If you request class scope for a test that is not part of a class, it will result in a *UsageError*.
 Similar to class-scoped event loops, a module-scoped loop is provided when setting mark's scope to *module:*
 
 .. include:: module_scoped_loop_strict_mode_example.py
     :code: python
 
-Package-scoped loops only work with `regular Python packages. <https://docs.python.org/3/glossary.html#term-regular-package>`__
-That means they require an *__init__.py* to be present.
-Package-scoped loops do not work in `namespace packages. <https://docs.python.org/3/glossary.html#term-namespace-package>`__
 Subpackages do not share the loop with their parent package.
 
 Tests marked with *session* scope share the same event loop, even if the tests exist in different packages.
diff -pruN 0.25.1-1/pyproject.toml 1.1.0-2/pyproject.toml
--- 0.25.1-1/pyproject.toml	2025-01-02 04:58:42.000000000 +0000
+++ 1.1.0-2/pyproject.toml	2025-07-16 03:50:17.000000000 +0000
@@ -1,10 +1,8 @@
 [build-system]
 build-backend = "setuptools.build_meta"
-
 requires = [
-  "setuptools>=51",
+  "setuptools>=77",
   "setuptools-scm[toml]>=6.2",
-  "wheel>=0.36",
 ]
 
 [project]
@@ -12,23 +10,29 @@ name = "pytest-asyncio"
 description = "Pytest support for asyncio"
 readme.content-type = "text/x-rst"
 readme.file = "README.rst"
-license.text = "Apache 2.0"
+license = "Apache-2.0"
+license-files = [
+  "LICENSE",
+]
+maintainers = [
+  { name = "Michael Seifert", email = "m.seifert@digitalernachschub.de" },
+]
 authors = [
-  { name = "Tin Tvrtković <tinchester@gmail.com>", email = "tinchester@gmail.com" },
+  { name = "Tin Tvrtković", email = "tinchester@gmail.com" },
 ]
 requires-python = ">=3.9"
 classifiers = [
-  "Development Status :: 4 - Beta",
+  "Development Status :: 5 - Production/Stable",
   "Framework :: AsyncIO",
   "Framework :: Pytest",
   "Intended Audience :: Developers",
-  "License :: OSI Approved :: Apache Software License",
   "Programming Language :: Python :: 3 :: Only",
   "Programming Language :: Python :: 3.9",
   "Programming Language :: Python :: 3.10",
   "Programming Language :: Python :: 3.11",
   "Programming Language :: Python :: 3.12",
   "Programming Language :: Python :: 3.13",
+  "Programming Language :: Python :: 3.14",
   "Topic :: Software Development :: Testing",
   "Typing :: Typed",
 ]
@@ -37,7 +41,9 @@ dynamic = [
 ]
 
 dependencies = [
+  "backports-asyncio-runner>=1.1,<2; python_version<'3.11'",
   "pytest>=8.2,<9",
+  "typing-extensions>=4.12; python_version<'3.10'",
 ]
 optional-dependencies.docs = [
   "sphinx>=5.3",
@@ -59,12 +65,10 @@ packages = [
   "pytest_asyncio",
 ]
 include-package-data = true
-license-files = [
-  "LICENSE",
-]
 
 [tool.setuptools_scm]
 write_to = "pytest_asyncio/_version.py"
+local_scheme = "no-local-version"
 
 [tool.ruff]
 line-length = 88
@@ -108,6 +112,9 @@ lint.ignore = [
   "D415", # First line should end with a period, question mark, or exclamation point
 ]
 
+[tool.pyproject-fmt]
+max_supported_python = "3.14"
+
 [tool.pytest.ini_options]
 python_files = [
   "test_*.py",
@@ -123,7 +130,6 @@ asyncio_default_fixture_loop_scope = "fu
 junit_family = "xunit2"
 filterwarnings = [
   "error",
-  "ignore:The event_loop fixture provided by pytest-asyncio has been redefined.*:DeprecationWarning",
 ]
 
 [tool.coverage.run]
@@ -139,3 +145,44 @@ parallel = true
 
 [tool.coverage.report]
 show_missing = true
+
+[tool.towncrier]
+directory = "changelog.d"
+filename = "docs/reference/changelog.rst"
+title_format = "`{version} <https://github.com/pytest-dev/pytest-asyncio/tree/{version}>`_ - {project_date}"
+issue_format = "`#{issue} <https://github.com/pytest-dev/pytest-asyncio/issues/{issue}>`_"
+
+[[tool.towncrier.type]]
+directory = "security"
+name = "Security"
+showcontent = true
+
+[[tool.towncrier.type]]
+directory = "removed"
+name = "Removed"
+showcontent = true
+
+[[tool.towncrier.type]]
+directory = "deprecated"
+name = "Deprecated"
+showcontent = true
+
+[[tool.towncrier.type]]
+directory = "added"
+name = "Added"
+showcontent = true
+
+[[tool.towncrier.type]]
+directory = "changed"
+name = "Changed"
+showcontent = true
+
+[[tool.towncrier.type]]
+directory = "fixed"
+name = "Fixed"
+showcontent = true
+
+[[tool.towncrier.type]]
+directory = "downstream"
+name = "Notes for Downstream Packagers"
+showcontent = true
diff -pruN 0.25.1-1/pytest_asyncio/plugin.py 1.1.0-2/pytest_asyncio/plugin.py
--- 0.25.1-1/pytest_asyncio/plugin.py	2025-01-02 04:58:42.000000000 +0000
+++ 1.1.0-2/pytest_asyncio/plugin.py	2025-07-16 03:50:17.000000000 +0000
@@ -9,19 +9,19 @@ import enum
 import functools
 import inspect
 import socket
+import sys
+import traceback
 import warnings
 from asyncio import AbstractEventLoop, AbstractEventLoopPolicy
 from collections.abc import (
     AsyncIterator,
     Awaitable,
-    Coroutine as AbstractCoroutine,
     Generator,
     Iterable,
     Iterator,
-    Mapping,
     Sequence,
 )
-from textwrap import dedent
+from types import AsyncGeneratorType, CoroutineType
 from typing import (
     Any,
     Callable,
@@ -33,47 +33,42 @@ from typing import (
 
 import pluggy
 import pytest
+from _pytest.fixtures import resolve_fixture_function
+from _pytest.scope import Scope
 from pytest import (
-    Class,
-    Collector,
     Config,
     FixtureDef,
     FixtureRequest,
     Function,
     Item,
     Mark,
-    Metafunc,
-    Module,
-    Package,
+    MonkeyPatch,
     Parser,
     PytestCollectionWarning,
     PytestDeprecationWarning,
     PytestPluginManager,
-    Session,
-    StashKey,
 )
 
-_ScopeName = Literal["session", "package", "module", "class", "function"]
-_T = TypeVar("_T")
+if sys.version_info >= (3, 10):
+    from typing import ParamSpec
+else:
+    from typing_extensions import ParamSpec
+
+if sys.version_info >= (3, 11):
+    from asyncio import Runner
+else:
+    from backports.asyncio.runner import Runner
 
-SimpleFixtureFunction = TypeVar(
-    "SimpleFixtureFunction", bound=Callable[..., Awaitable[object]]
-)
-FactoryFixtureFunction = TypeVar(
-    "FactoryFixtureFunction", bound=Callable[..., AsyncIterator[object]]
-)
-FixtureFunction = Union[SimpleFixtureFunction, FactoryFixtureFunction]
-FixtureFunctionMarker = Callable[[FixtureFunction], FixtureFunction]
+_ScopeName = Literal["session", "package", "module", "class", "function"]
+_R = TypeVar("_R", bound=Union[Awaitable[Any], AsyncIterator[Any]])
+_P = ParamSpec("_P")
+FixtureFunction = Callable[_P, _R]
 
 
 class PytestAsyncioError(Exception):
     """Base class for exceptions raised by pytest-asyncio"""
 
 
-class MultipleEventLoopsRequestedError(PytestAsyncioError):
-    """Raised when a test requests multiple asyncio event loops."""
-
-
 class Mode(str, enum.Enum):
     AUTO = "auto"
     STRICT = "strict"
@@ -107,11 +102,17 @@ def pytest_addoption(parser: Parser, plu
         help="default scope of the asyncio event loop used to execute async fixtures",
         default=None,
     )
+    parser.addini(
+        "asyncio_default_test_loop_scope",
+        type="string",
+        help="default scope of the asyncio event loop used to execute tests",
+        default="function",
+    )
 
 
 @overload
 def fixture(
-    fixture_function: FixtureFunction,
+    fixture_function: FixtureFunction[_P, _R],
     *,
     scope: _ScopeName | Callable[[str, Config], _ScopeName] = ...,
     loop_scope: _ScopeName | None = ...,
@@ -123,7 +124,7 @@ def fixture(
         | None
     ) = ...,
     name: str | None = ...,
-) -> FixtureFunction: ...
+) -> FixtureFunction[_P, _R]: ...
 
 
 @overload
@@ -140,14 +141,17 @@ def fixture(
         | None
     ) = ...,
     name: str | None = None,
-) -> FixtureFunctionMarker: ...
+) -> Callable[[FixtureFunction[_P, _R]], FixtureFunction[_P, _R]]: ...
 
 
 def fixture(
-    fixture_function: FixtureFunction | None = None,
+    fixture_function: FixtureFunction[_P, _R] | None = None,
     loop_scope: _ScopeName | None = None,
     **kwargs: Any,
-) -> FixtureFunction | FixtureFunctionMarker:
+) -> (
+    FixtureFunction[_P, _R]
+    | Callable[[FixtureFunction[_P, _R]], FixtureFunction[_P, _R]]
+):
     if fixture_function is not None:
         _make_asyncio_fixture_function(fixture_function, loop_scope)
         return pytest.fixture(fixture_function, **kwargs)
@@ -155,7 +159,7 @@ def fixture(
     else:
 
         @functools.wraps(fixture)
-        def inner(fixture_function: FixtureFunction) -> FixtureFunction:
+        def inner(fixture_function: FixtureFunction[_P, _R]) -> FixtureFunction[_P, _R]:
             return fixture(fixture_function, loop_scope=loop_scope, **kwargs)
 
         return inner
@@ -217,116 +221,55 @@ def pytest_configure(config: Config) ->
 def pytest_report_header(config: Config) -> list[str]:
     """Add asyncio config to pytest header."""
     mode = _get_asyncio_mode(config)
-    default_loop_scope = config.getini("asyncio_default_fixture_loop_scope")
+    default_fixture_loop_scope = config.getini("asyncio_default_fixture_loop_scope")
+    default_test_loop_scope = _get_default_test_loop_scope(config)
+    header = [
+        f"mode={mode}",
+        f"asyncio_default_fixture_loop_scope={default_fixture_loop_scope}",
+        f"asyncio_default_test_loop_scope={default_test_loop_scope}",
+    ]
     return [
-        f"asyncio: mode={mode}, asyncio_default_fixture_loop_scope={default_loop_scope}"
+        "asyncio: " + ", ".join(header),
     ]
 
 
-def _preprocess_async_fixtures(
-    collector: Collector,
-    processed_fixturedefs: set[FixtureDef],
-) -> None:
-    config = collector.config
-    default_loop_scope = config.getini("asyncio_default_fixture_loop_scope")
-    asyncio_mode = _get_asyncio_mode(config)
-    fixturemanager = config.pluginmanager.get_plugin("funcmanage")
-    assert fixturemanager is not None
-    for fixtures in fixturemanager._arg2fixturedefs.values():
-        for fixturedef in fixtures:
-            func = fixturedef.func
-            if fixturedef in processed_fixturedefs or not _is_coroutine_or_asyncgen(
-                func
-            ):
-                continue
-            if asyncio_mode == Mode.STRICT and not _is_asyncio_fixture_function(func):
-                # Ignore async fixtures without explicit asyncio mark in strict mode
-                # This applies to pytest_trio fixtures, for example
-                continue
-            scope = (
-                getattr(func, "_loop_scope", None)
-                or default_loop_scope
-                or fixturedef.scope
-            )
-            if scope == "function" and "event_loop" not in fixturedef.argnames:
-                fixturedef.argnames += ("event_loop",)
-            _make_asyncio_fixture_function(func, scope)
-            function_signature = inspect.signature(func)
-            if "event_loop" in function_signature.parameters:
-                warnings.warn(
-                    PytestDeprecationWarning(
-                        f"{func.__name__} is asynchronous and explicitly "
-                        f'requests the "event_loop" fixture. Asynchronous fixtures and '
-                        f'test functions should use "asyncio.get_running_loop()" '
-                        f"instead."
-                    )
-                )
-            if "request" not in fixturedef.argnames:
-                fixturedef.argnames += ("request",)
-            _synchronize_async_fixture(fixturedef)
-            assert _is_asyncio_fixture_function(fixturedef.func)
-            processed_fixturedefs.add(fixturedef)
-
-
-def _synchronize_async_fixture(fixturedef: FixtureDef) -> None:
-    """Wraps the fixture function of an async fixture in a synchronous function."""
+def _fixture_synchronizer(
+    fixturedef: FixtureDef, runner: Runner, request: FixtureRequest
+) -> Callable:
+    """Returns a synchronous function evaluating the specified fixture."""
+    fixture_function = resolve_fixture_function(fixturedef, request)
     if inspect.isasyncgenfunction(fixturedef.func):
-        _wrap_asyncgen_fixture(fixturedef)
+        return _wrap_asyncgen_fixture(fixture_function, runner, request)  # type: ignore[arg-type]
     elif inspect.iscoroutinefunction(fixturedef.func):
-        _wrap_async_fixture(fixturedef)
-
-
-def _add_kwargs(
-    func: Callable[..., Any],
-    kwargs: dict[str, Any],
-    event_loop: asyncio.AbstractEventLoop,
-    request: FixtureRequest,
-) -> dict[str, Any]:
-    sig = inspect.signature(func)
-    ret = kwargs.copy()
-    if "request" in sig.parameters:
-        ret["request"] = request
-    if "event_loop" in sig.parameters:
-        ret["event_loop"] = event_loop
-    return ret
+        return _wrap_async_fixture(fixture_function, runner, request)  # type: ignore[arg-type]
+    else:
+        return fixturedef.func
 
 
-def _perhaps_rebind_fixture_func(func: _T, instance: Any | None) -> _T:
-    if instance is not None:
-        # The fixture needs to be bound to the actual request.instance
-        # so it is bound to the same object as the test method.
-        unbound, cls = func, None
-        try:
-            unbound, cls = func.__func__, type(func.__self__)  # type: ignore
-        except AttributeError:
-            pass
-        # Only if the fixture was bound before to an instance of
-        # the same type.
-        if cls is not None and isinstance(instance, cls):
-            func = unbound.__get__(instance)  # type: ignore
-    return func
+AsyncGenFixtureParams = ParamSpec("AsyncGenFixtureParams")
+AsyncGenFixtureYieldType = TypeVar("AsyncGenFixtureYieldType")
 
 
-def _wrap_asyncgen_fixture(fixturedef: FixtureDef) -> None:
-    fixture = fixturedef.func
-
-    @functools.wraps(fixture)
-    def _asyncgen_fixture_wrapper(request: FixtureRequest, **kwargs: Any):
-        func = _perhaps_rebind_fixture_func(fixture, request.instance)
-        event_loop_fixture_id = _get_event_loop_fixture_id_for_async_fixture(
-            request, func
-        )
-        event_loop = request.getfixturevalue(event_loop_fixture_id)
-        kwargs.pop(event_loop_fixture_id, None)
-        gen_obj = func(**_add_kwargs(func, kwargs, event_loop, request))
+def _wrap_asyncgen_fixture(
+    fixture_function: Callable[
+        AsyncGenFixtureParams, AsyncGeneratorType[AsyncGenFixtureYieldType, Any]
+    ],
+    runner: Runner,
+    request: FixtureRequest,
+) -> Callable[AsyncGenFixtureParams, AsyncGenFixtureYieldType]:
+    @functools.wraps(fixture_function)
+    def _asyncgen_fixture_wrapper(
+        *args: AsyncGenFixtureParams.args,
+        **kwargs: AsyncGenFixtureParams.kwargs,
+    ):
+        gen_obj = fixture_function(*args, **kwargs)
 
         async def setup():
             res = await gen_obj.__anext__()  # type: ignore[union-attr]
             return res
 
         context = contextvars.copy_context()
-        setup_task = _create_task_in_context(event_loop, setup(), context)
-        result = event_loop.run_until_complete(setup_task)
+        result = runner.run(setup(), context=context)
 
         reset_contextvars = _apply_contextvar_changes(context)
 
@@ -343,36 +286,39 @@ def _wrap_asyncgen_fixture(fixturedef: F
                     msg += "Yield only once."
                     raise ValueError(msg)
 
-            task = _create_task_in_context(event_loop, async_finalizer(), context)
-            event_loop.run_until_complete(task)
+            runner.run(async_finalizer(), context=context)
             if reset_contextvars is not None:
                 reset_contextvars()
 
         request.addfinalizer(finalizer)
         return result
 
-    fixturedef.func = _asyncgen_fixture_wrapper  # type: ignore[misc]
+    return _asyncgen_fixture_wrapper
 
 
-def _wrap_async_fixture(fixturedef: FixtureDef) -> None:
-    fixture = fixturedef.func
+AsyncFixtureParams = ParamSpec("AsyncFixtureParams")
+AsyncFixtureReturnType = TypeVar("AsyncFixtureReturnType")
 
-    @functools.wraps(fixture)
-    def _async_fixture_wrapper(request: FixtureRequest, **kwargs: Any):
-        func = _perhaps_rebind_fixture_func(fixture, request.instance)
-        event_loop_fixture_id = _get_event_loop_fixture_id_for_async_fixture(
-            request, func
-        )
-        event_loop = request.getfixturevalue(event_loop_fixture_id)
-        kwargs.pop(event_loop_fixture_id, None)
 
+def _wrap_async_fixture(
+    fixture_function: Callable[
+        AsyncFixtureParams, CoroutineType[Any, Any, AsyncFixtureReturnType]
+    ],
+    runner: Runner,
+    request: FixtureRequest,
+) -> Callable[AsyncFixtureParams, AsyncFixtureReturnType]:
+
+    @functools.wraps(fixture_function)  # type: ignore[arg-type]
+    def _async_fixture_wrapper(
+        *args: AsyncFixtureParams.args,
+        **kwargs: AsyncFixtureParams.kwargs,
+    ):
         async def setup():
-            res = await func(**_add_kwargs(func, kwargs, event_loop, request))
+            res = await fixture_function(*args, **kwargs)
             return res
 
         context = contextvars.copy_context()
-        setup_task = _create_task_in_context(event_loop, setup(), context)
-        result = event_loop.run_until_complete(setup_task)
+        result = runner.run(setup(), context=context)
 
         # Copy the context vars modified by the setup task into the current
         # context, and (if needed) add a finalizer to reset them.
@@ -388,50 +334,7 @@ def _wrap_async_fixture(fixturedef: Fixt
 
         return result
 
-    fixturedef.func = _async_fixture_wrapper  # type: ignore[misc]
-
-
-def _get_event_loop_fixture_id_for_async_fixture(
-    request: FixtureRequest, func: Any
-) -> str:
-    default_loop_scope = request.config.getini("asyncio_default_fixture_loop_scope")
-    loop_scope = (
-        getattr(func, "_loop_scope", None) or default_loop_scope or request.scope
-    )
-    if loop_scope == "function":
-        event_loop_fixture_id = "event_loop"
-    else:
-        event_loop_node = _retrieve_scope_root(request._pyfuncitem, loop_scope)
-        event_loop_fixture_id = event_loop_node.stash.get(
-            # Type ignored because of non-optimal mypy inference.
-            _event_loop_fixture_id,  # type: ignore[arg-type]
-            "",
-        )
-    assert event_loop_fixture_id
-    return event_loop_fixture_id
-
-
-def _create_task_in_context(
-    loop: asyncio.AbstractEventLoop,
-    coro: AbstractCoroutine[Any, Any, _T],
-    context: contextvars.Context,
-) -> asyncio.Task[_T]:
-    """
-    Return an asyncio task that runs the coro in the specified context,
-    if possible.
-
-    This allows fixture setup and teardown to be run as separate asyncio tasks,
-    while still being able to use context-manager idioms to maintain context
-    variables and make those variables visible to test functions.
-
-    This is only fully supported on Python 3.11 and newer, as it requires
-    the API added for https://github.com/python/cpython/issues/91150.
-    On earlier versions, the returned task will use the default context instead.
-    """
-    try:
-        return loop.create_task(coro, context=context)
-    except TypeError:
-        return loop.create_task(coro)
+    return _async_fixture_wrapper
 
 
 def _apply_contextvar_changes(
@@ -500,15 +403,6 @@ class PytestAsyncioFunction(Function):
         )
         subclass_instance.own_markers = function.own_markers
         assert subclass_instance.own_markers == function.own_markers
-        subclassed_function_signature = inspect.signature(subclass_instance.obj)
-        if "event_loop" in subclassed_function_signature.parameters:
-            subclass_instance.warn(
-                PytestDeprecationWarning(
-                    f"{subclass_instance.name} is asynchronous and explicitly "
-                    f'requests the "event_loop" fixture. Asynchronous fixtures and '
-                    f'test functions should use "asyncio.get_running_loop()" instead.'
-                )
-            )
         return subclass_instance
 
     @staticmethod
@@ -526,11 +420,10 @@ class Coroutine(PytestAsyncioFunction):
         return inspect.iscoroutinefunction(func)
 
     def runtest(self) -> None:
-        self.obj = wrap_in_sync(
-            # https://github.com/pytest-dev/pytest-asyncio/issues/596
-            self.obj,  # type: ignore[has-type]
-        )
-        super().runtest()
+        synchronized_obj = wrap_in_sync(self.obj)
+        with MonkeyPatch.context() as c:
+            c.setattr(self, "obj", synchronized_obj)
+            super().runtest()
 
 
 class AsyncGenerator(PytestAsyncioFunction):
@@ -569,11 +462,10 @@ class AsyncStaticMethod(PytestAsyncioFun
         )
 
     def runtest(self) -> None:
-        self.obj = wrap_in_sync(
-            # https://github.com/pytest-dev/pytest-asyncio/issues/596
-            self.obj,  # type: ignore[has-type]
-        )
-        super().runtest()
+        synchronized_obj = wrap_in_sync(self.obj)
+        with MonkeyPatch.context() as c:
+            c.setattr(self, "obj", synchronized_obj)
+            super().runtest()
 
 
 class AsyncHypothesisTest(PytestAsyncioFunction):
@@ -592,26 +484,10 @@ class AsyncHypothesisTest(PytestAsyncioF
         )
 
     def runtest(self) -> None:
-        self.obj.hypothesis.inner_test = wrap_in_sync(
-            self.obj.hypothesis.inner_test,
-        )
-        super().runtest()
-
-
-_HOLDER: set[FixtureDef] = set()
-
-
-# The function name needs to start with "pytest_"
-# see https://github.com/pytest-dev/pytest/issues/11307
-@pytest.hookimpl(specname="pytest_pycollect_makeitem", tryfirst=True)
-def pytest_pycollect_makeitem_preprocess_async_fixtures(
-    collector: pytest.Module | pytest.Class, name: str, obj: object
-) -> pytest.Item | pytest.Collector | list[pytest.Item | pytest.Collector] | None:
-    """A pytest hook to collect asyncio coroutines."""
-    if not collector.funcnamefilter(name):
-        return None
-    _preprocess_async_fixtures(collector, _HOLDER)
-    return None
+        synchronized_obj = wrap_in_sync(self.obj.hypothesis.inner_test)
+        with MonkeyPatch.context() as c:
+            c.setattr(self.obj.hypothesis, "inner_test", synchronized_obj)
+            super().runtest()
 
 
 # The function name needs to start with "pytest_"
@@ -655,316 +531,31 @@ def pytest_pycollect_makeitem_convert_as
     hook_result.force_result(updated_node_collection)
 
 
-_event_loop_fixture_id = StashKey[str]()
-_fixture_scope_by_collector_type: Mapping[type[pytest.Collector], _ScopeName] = {
-    Class: "class",
-    # Package is a subclass of module and the dict is used in isinstance checks
-    # Therefore, the order matters and Package needs to appear before Module
-    Package: "package",
-    Module: "module",
-    Session: "session",
-}
-
-# A stack used to push package-scoped loops during collection of a package
-# and pop those loops during collection of a Module
-__package_loop_stack: list[FixtureFunctionMarker | FixtureFunction] = []
-
-
-@pytest.hookimpl
-def pytest_collectstart(collector: pytest.Collector) -> None:
-    try:
-        collector_scope = next(
-            scope
-            for cls, scope in _fixture_scope_by_collector_type.items()
-            if isinstance(collector, cls)
-        )
-    except StopIteration:
-        return
-    # Session is not a PyCollector type, so it doesn't have a corresponding
-    # "obj" attribute to attach a dynamic fixture function to.
-    # However, there's only one session per pytest run, so there's no need to
-    # create the fixture dynamically. We can simply define a session-scoped
-    # event loop fixture once in the plugin code.
-    if collector_scope == "session":
-        event_loop_fixture_id = _session_event_loop.__name__
-        collector.stash[_event_loop_fixture_id] = event_loop_fixture_id
-        return
-    # There seem to be issues when a fixture is shadowed by another fixture
-    # and both differ in their params.
-    # https://github.com/pytest-dev/pytest/issues/2043
-    # https://github.com/pytest-dev/pytest/issues/11350
-    # As such, we assign a unique name for each event_loop fixture.
-    # The fixture name is stored in the collector's Stash, so it can
-    # be injected when setting up the test
-    event_loop_fixture_id = f"{collector.nodeid}::<event_loop>"
-    collector.stash[_event_loop_fixture_id] = event_loop_fixture_id
-
-    @pytest.fixture(
-        scope=collector_scope,
-        name=event_loop_fixture_id,
-    )
-    def scoped_event_loop(
-        *args,  # Function needs to accept "cls" when collected by pytest.Class
-        event_loop_policy,
-    ) -> Iterator[asyncio.AbstractEventLoop]:
-        new_loop_policy = event_loop_policy
-        with _temporary_event_loop_policy(new_loop_policy):
-            loop = _make_pytest_asyncio_loop(asyncio.new_event_loop())
-            asyncio.set_event_loop(loop)
-            yield loop
-            loop.close()
-
-    # @pytest.fixture does not register the fixture anywhere, so pytest doesn't
-    # know it exists. We work around this by attaching the fixture function to the
-    # collected Python object, where it will be picked up by pytest.Class.collect()
-    # or pytest.Module.collect(), respectively
-    if type(collector) is Package:
-        # Packages do not have a corresponding Python object. Therefore, the fixture
-        # for the package-scoped event loop is added to a stack. When a module inside
-        # the package is collected, the module will attach the fixture to its
-        # Python object.
-        __package_loop_stack.append(scoped_event_loop)
-    elif isinstance(collector, Module):
-        # Accessing Module.obj triggers a module import executing module-level
-        # statements. A module-level pytest.skip statement raises the "Skipped"
-        # OutcomeException or a Collector.CollectError, if the "allow_module_level"
-        # kwargs is missing. These cases are handled correctly when they happen inside
-        # Collector.collect(), but this hook runs before the actual collect call.
-        # Therefore, we monkey patch Module.collect to add the scoped fixture to the
-        # module before it runs the actual collection.
-        def _patched_collect():
-            # If the collected module is a DoctestTextfile, collector.obj is None
-            module = collector.obj
-            if module is not None:
-                module.__pytest_asyncio_scoped_event_loop = scoped_event_loop
-                try:
-                    package_loop = __package_loop_stack.pop()
-                    module.__pytest_asyncio_package_scoped_event_loop = package_loop
-                except IndexError:
-                    pass
-            return collector.__original_collect()
-
-        collector.__original_collect = collector.collect  # type: ignore[attr-defined]
-        collector.collect = _patched_collect  # type: ignore[method-assign]
-    elif isinstance(collector, Class):
-        collector.obj.__pytest_asyncio_scoped_event_loop = scoped_event_loop
-
-
 @contextlib.contextmanager
 def _temporary_event_loop_policy(policy: AbstractEventLoopPolicy) -> Iterator[None]:
-    old_loop_policy = asyncio.get_event_loop_policy()
+    old_loop_policy = _get_event_loop_policy()
     try:
         old_loop = _get_event_loop_no_warn()
     except RuntimeError:
         old_loop = None
-    asyncio.set_event_loop_policy(policy)
+    _set_event_loop_policy(policy)
     try:
         yield
     finally:
-        # Try detecting user-created event loops that were left unclosed
-        # at the end of a test.
-        try:
-            current_loop: AbstractEventLoop | None = _get_event_loop_no_warn()
-        except RuntimeError:
-            current_loop = None
-        if current_loop is not None and not current_loop.is_closed():
-            warnings.warn(
-                _UNCLOSED_EVENT_LOOP_WARNING % current_loop,
-                DeprecationWarning,
-            )
-            current_loop.close()
-
-        asyncio.set_event_loop_policy(old_loop_policy)
-        # When a test uses both a scoped event loop and the event_loop fixture,
-        # the "_provide_clean_event_loop" finalizer of the event_loop fixture
-        # will already have installed a fresh event loop, in order to shield
-        # subsequent tests from side-effects. We close this loop before restoring
-        # the old loop to avoid ResourceWarnings.
-        try:
-            _get_event_loop_no_warn().close()
-        except RuntimeError:
-            pass
-        asyncio.set_event_loop(old_loop)
-
-
-_REDEFINED_EVENT_LOOP_FIXTURE_WARNING = dedent(
-    """\
-    The event_loop fixture provided by pytest-asyncio has been redefined in
-    %s:%d
-    Replacing the event_loop fixture with a custom implementation is deprecated
-    and will lead to errors in the future.
-    If you want to request an asyncio event loop with a scope other than function
-    scope, use the "loop_scope" argument to the asyncio mark when marking the tests.
-    If you want to return different types of event loops, use the event_loop_policy
-    fixture.
-    """
-)
-
-
-@pytest.hookimpl(tryfirst=True)
-def pytest_generate_tests(metafunc: Metafunc) -> None:
-    marker = metafunc.definition.get_closest_marker("asyncio")
-    if not marker:
-        return
-    scope = _get_marked_loop_scope(marker)
-    if scope == "function":
-        return
-    event_loop_node = _retrieve_scope_root(metafunc.definition, scope)
-    event_loop_fixture_id = event_loop_node.stash.get(_event_loop_fixture_id, None)
-
-    if event_loop_fixture_id:
-        # This specific fixture name may already be in metafunc.argnames, if this
-        # test indirectly depends on the fixture. For example, this is the case
-        # when the test depends on an async fixture, both of which share the same
-        # event loop fixture mark.
-        if event_loop_fixture_id in metafunc.fixturenames:
-            return
-        fixturemanager = metafunc.config.pluginmanager.get_plugin("funcmanage")
-        assert fixturemanager is not None
-        if "event_loop" in metafunc.fixturenames:
-            raise MultipleEventLoopsRequestedError(
-                _MULTIPLE_LOOPS_REQUESTED_ERROR.format(
-                    test_name=metafunc.definition.nodeid,
-                    scope=scope,
-                    scoped_loop_node=event_loop_node.nodeid,
-                ),
-            )
-        # Add the scoped event loop fixture to Metafunc's list of fixture names and
-        # fixturedefs and leave the actual parametrization to pytest
-        # The fixture needs to be appended to avoid messing up the fixture evaluation
-        # order
-        metafunc.fixturenames.append(event_loop_fixture_id)
-        metafunc._arg2fixturedefs[event_loop_fixture_id] = (
-            fixturemanager._arg2fixturedefs[event_loop_fixture_id]
-        )
-
-
-@pytest.hookimpl(hookwrapper=True)
-def pytest_fixture_setup(
-    fixturedef: FixtureDef,
-) -> Generator[None, pluggy.Result, None]:
-    """Adjust the event loop policy when an event loop is produced."""
-    if fixturedef.argname == "event_loop":
-        # The use of a fixture finalizer is preferred over the
-        # pytest_fixture_post_finalizer hook. The fixture finalizer is invoked once
-        # for each fixture, whereas the hook may be invoked multiple times for
-        # any specific fixture.
-        # see https://github.com/pytest-dev/pytest/issues/5848
-        _add_finalizers(
-            fixturedef,
-            _close_event_loop,
-            _restore_event_loop_policy(asyncio.get_event_loop_policy()),
-            _provide_clean_event_loop,
-        )
-        outcome = yield
-        loop: asyncio.AbstractEventLoop = outcome.get_result()
-        # Weird behavior was observed when checking for an attribute of FixtureDef.func
-        # Instead, we now check for a special attribute of the returned event loop
-        fixture_filename = inspect.getsourcefile(fixturedef.func)
-        if not _is_pytest_asyncio_loop(loop):
-            _, fixture_line_number = inspect.getsourcelines(fixturedef.func)
-            warnings.warn(
-                _REDEFINED_EVENT_LOOP_FIXTURE_WARNING
-                % (fixture_filename, fixture_line_number),
-                DeprecationWarning,
-            )
-        policy = asyncio.get_event_loop_policy()
-        try:
-            old_loop = _get_event_loop_no_warn(policy)
-            if old_loop is not loop and not _is_pytest_asyncio_loop(old_loop):
-                old_loop.close()
-        except RuntimeError:
-            # Either the current event loop has been set to None
-            # or the loop policy doesn't specify to create new loops
-            # or we're not in the main thread
-            pass
-        policy.set_event_loop(loop)
-        return
-
-    yield
-
-
-def _make_pytest_asyncio_loop(loop: AbstractEventLoop) -> AbstractEventLoop:
-    loop.__pytest_asyncio = True  # type: ignore[attr-defined]
-    return loop
-
-
-def _is_pytest_asyncio_loop(loop: AbstractEventLoop) -> bool:
-    return getattr(loop, "__pytest_asyncio", False)
-
-
-def _add_finalizers(fixturedef: FixtureDef, *finalizers: Callable[[], object]) -> None:
-    """
-    Registers the specified fixture finalizers in the fixture.
-
-    Finalizers need to be specified in the exact order in which they should be invoked.
-
-    :param fixturedef: Fixture definition which finalizers should be added to
-    :param finalizers: Finalizers to be added
-    """
-    for finalizer in reversed(finalizers):
-        fixturedef.addfinalizer(finalizer)
-
-
-_UNCLOSED_EVENT_LOOP_WARNING = dedent(
-    """\
-    pytest-asyncio detected an unclosed event loop when tearing down the event_loop
-    fixture: %r
-    pytest-asyncio will close the event loop for you, but future versions of the
-    library will no longer do so. In order to ensure compatibility with future
-    versions, please make sure that:
-        1. Any custom "event_loop" fixture properly closes the loop after yielding it
-        2. The scopes of your custom "event_loop" fixtures do not overlap
-        3. Your code does not modify the event loop in async fixtures or tests
-    """
-)
+        _set_event_loop_policy(old_loop_policy)
+        _set_event_loop(old_loop)
 
 
-def _close_event_loop() -> None:
-    policy = asyncio.get_event_loop_policy()
-    try:
-        loop = policy.get_event_loop()
-    except RuntimeError:
-        loop = None
-    if loop is not None and not _is_pytest_asyncio_loop(loop):
-        if not loop.is_closed():
-            warnings.warn(
-                _UNCLOSED_EVENT_LOOP_WARNING % loop,
-                DeprecationWarning,
-            )
-        loop.close()
+def _get_event_loop_policy() -> AbstractEventLoopPolicy:
+    with warnings.catch_warnings():
+        warnings.simplefilter("ignore", DeprecationWarning)
+        return asyncio.get_event_loop_policy()
 
 
-def _restore_event_loop_policy(previous_policy) -> Callable[[], None]:
-    def _restore_policy():
-        # Close any event loop associated with the old loop policy
-        # to avoid ResourceWarnings in the _provide_clean_event_loop finalizer
-        try:
-            loop = _get_event_loop_no_warn(previous_policy)
-        except RuntimeError:
-            loop = None
-        if loop and not _is_pytest_asyncio_loop(loop):
-            loop.close()
-        asyncio.set_event_loop_policy(previous_policy)
-
-    return _restore_policy
-
-
-def _provide_clean_event_loop() -> None:
-    # At this point, the event loop for the current thread is closed.
-    # When a user calls asyncio.get_event_loop(), they will get a closed loop.
-    # In order to avoid this side effect from pytest-asyncio, we need to replace
-    # the current loop with a fresh one.
-    # Note that we cannot set the loop to None, because get_event_loop only creates
-    # a new loop, when set_event_loop has not been called.
-    policy = asyncio.get_event_loop_policy()
-    try:
-        old_loop = _get_event_loop_no_warn(policy)
-    except RuntimeError:
-        old_loop = None
-    if old_loop is not None and not _is_pytest_asyncio_loop(old_loop):
-        new_loop = policy.new_event_loop()
-        policy.set_event_loop(new_loop)
+def _set_event_loop_policy(policy: AbstractEventLoopPolicy) -> None:
+    with warnings.catch_warnings():
+        warnings.simplefilter("ignore", DeprecationWarning)
+        asyncio.set_event_loop_policy(policy)
 
 
 def _get_event_loop_no_warn(
@@ -978,6 +569,12 @@ def _get_event_loop_no_warn(
             return asyncio.get_event_loop()
 
 
+def _set_event_loop(loop: AbstractEventLoop | None) -> None:
+    with warnings.catch_warnings():
+        warnings.simplefilter("ignore", DeprecationWarning)
+        asyncio.set_event_loop(loop)
+
+
 @pytest.hookimpl(tryfirst=True, hookwrapper=True)
 def pytest_pyfunc_call(pyfuncitem: Function) -> object | None:
     """
@@ -1035,12 +632,6 @@ def wrap_in_sync(
     Return a sync wrapper around an async function executing it in the
     current event loop.
     """
-    # if the function is already wrapped, we rewrap using the original one
-    # not using __wrapped__ because the original function may already be
-    # a wrapped one
-    raw_func = getattr(func, "_raw_test_func", None)
-    if raw_func is not None:
-        func = raw_func
 
     @functools.wraps(func)
     def inner(*args, **kwargs):
@@ -1057,35 +648,19 @@ def wrap_in_sync(
                 task.exception()
             raise
 
-    inner._raw_test_func = func  # type: ignore[attr-defined]
     return inner
 
 
-_MULTIPLE_LOOPS_REQUESTED_ERROR = dedent(
-    """\
-        Multiple asyncio event loops with different scopes have been requested
-        by {test_name}. The test explicitly requests the event_loop fixture, while
-        another event loop with {scope} scope is provided by {scoped_loop_node}.
-        Remove "event_loop" from the requested fixture in your test to run the test
-        in a {scope}-scoped event loop or remove the scope argument from the "asyncio"
-        mark to run the test in a function-scoped event loop.
-    """
-)
-
-
 def pytest_runtest_setup(item: pytest.Item) -> None:
     marker = item.get_closest_marker("asyncio")
     if marker is None:
         return
-    scope = _get_marked_loop_scope(marker)
-    if scope != "function":
-        parent_node = _retrieve_scope_root(item, scope)
-        event_loop_fixture_id = parent_node.stash[_event_loop_fixture_id]
-    else:
-        event_loop_fixture_id = "event_loop"
+    default_loop_scope = _get_default_test_loop_scope(item.config)
+    loop_scope = _get_marked_loop_scope(marker, default_loop_scope)
+    runner_fixture_id = f"_{loop_scope}_scoped_runner"
     fixturenames = item.fixturenames  # type: ignore[attr-defined]
-    if event_loop_fixture_id not in fixturenames:
-        fixturenames.append(event_loop_fixture_id)
+    if runner_fixture_id not in fixturenames:
+        fixturenames.append(runner_fixture_id)
     obj = getattr(item, "obj", None)
     if not getattr(obj, "hypothesis", False) and getattr(
         obj, "is_hypothesis_test", False
@@ -1096,6 +671,32 @@ def pytest_runtest_setup(item: pytest.It
         )
 
 
+@pytest.hookimpl(wrapper=True)
+def pytest_fixture_setup(fixturedef: FixtureDef, request) -> object | None:
+    asyncio_mode = _get_asyncio_mode(request.config)
+    if not _is_asyncio_fixture_function(fixturedef.func):
+        if asyncio_mode == Mode.STRICT:
+            # Ignore async fixtures without explicit asyncio mark in strict mode
+            # This applies to pytest_trio fixtures, for example
+            return (yield)
+        if not _is_coroutine_or_asyncgen(fixturedef.func):
+            return (yield)
+    default_loop_scope = request.config.getini("asyncio_default_fixture_loop_scope")
+    loop_scope = (
+        getattr(fixturedef.func, "_loop_scope", None)
+        or default_loop_scope
+        or fixturedef.scope
+    )
+    runner_fixture_id = f"_{loop_scope}_scoped_runner"
+    runner = request.getfixturevalue(runner_fixture_id)
+    synchronizer = _fixture_synchronizer(fixturedef, runner, request)
+    _make_asyncio_fixture_function(synchronizer, loop_scope)
+    with MonkeyPatch.context() as c:
+        c.setattr(fixturedef, "func", synchronizer)
+        hook_result = yield
+    return hook_result
+
+
 _DUPLICATE_LOOP_SCOPE_DEFINITION_ERROR = """\
 An asyncio pytest marker defines both "scope" and "loop_scope", \
 but it should only use "loop_scope".
@@ -1107,7 +708,9 @@ Please use the "loop_scope" argument ins
 """
 
 
-def _get_marked_loop_scope(asyncio_marker: Mark) -> _ScopeName:
+def _get_marked_loop_scope(
+    asyncio_marker: Mark, default_loop_scope: _ScopeName
+) -> _ScopeName:
     assert asyncio_marker.name == "asyncio"
     if asyncio_marker.args or (
         asyncio_marker.kwargs and set(asyncio_marker.kwargs) - {"loop_scope", "scope"}
@@ -1118,63 +721,70 @@ def _get_marked_loop_scope(asyncio_marke
             raise pytest.UsageError(_DUPLICATE_LOOP_SCOPE_DEFINITION_ERROR)
         warnings.warn(PytestDeprecationWarning(_MARKER_SCOPE_KWARG_DEPRECATION_WARNING))
     scope = asyncio_marker.kwargs.get("loop_scope") or asyncio_marker.kwargs.get(
-        "scope", "function"
+        "scope"
     )
+    if scope is None:
+        scope = default_loop_scope
     assert scope in {"function", "class", "module", "package", "session"}
     return scope
 
 
-def _retrieve_scope_root(item: Collector | Item, scope: str) -> Collector:
-    node_type_by_scope = {
-        "class": Class,
-        "module": Module,
-        "package": Package,
-        "session": Session,
-    }
-    scope_root_type = node_type_by_scope[scope]
-    for node in reversed(item.listchain()):
-        if isinstance(node, scope_root_type):
-            assert isinstance(node, pytest.Collector)
-            return node
-    error_message = (
-        f"{item.name} is marked to be run in an event loop with scope {scope}, "
-        f"but is not part of any {scope}."
+def _get_default_test_loop_scope(config: Config) -> _ScopeName:
+    return config.getini("asyncio_default_test_loop_scope")
+
+
+_RUNNER_TEARDOWN_WARNING = """\
+An exception occurred during teardown of an asyncio.Runner. \
+The reason is likely that you closed the underlying event loop in a test, \
+which prevents the cleanup of asynchronous generators by the runner.
+This warning will become an error in future versions of pytest-asyncio. \
+Please ensure that your tests don't close the event loop. \
+Here is the traceback of the exception triggered during teardown:
+%s
+"""
+
+
+def _create_scoped_runner_fixture(scope: _ScopeName) -> Callable:
+    @pytest.fixture(
+        scope=scope,
+        name=f"_{scope}_scoped_runner",
     )
-    raise pytest.UsageError(error_message)
+    def _scoped_runner(
+        event_loop_policy,
+    ) -> Iterator[Runner]:
+        new_loop_policy = event_loop_policy
+        with _temporary_event_loop_policy(new_loop_policy):
+            runner = Runner().__enter__()
+            try:
+                yield runner
+            except Exception as e:
+                runner.__exit__(type(e), e, e.__traceback__)
+            else:
+                with warnings.catch_warnings():
+                    warnings.filterwarnings(
+                        "ignore", ".*BaseEventLoop.shutdown_asyncgens.*", RuntimeWarning
+                    )
+                    try:
+                        runner.__exit__(None, None, None)
+                    except RuntimeError:
+                        warnings.warn(
+                            _RUNNER_TEARDOWN_WARNING % traceback.format_exc(),
+                            RuntimeWarning,
+                        )
+
+    return _scoped_runner
 
 
-@pytest.fixture
-def event_loop(request: FixtureRequest) -> Iterator[asyncio.AbstractEventLoop]:
-    """Create an instance of the default event loop for each test case."""
-    new_loop_policy = request.getfixturevalue(event_loop_policy.__name__)
-    with _temporary_event_loop_policy(new_loop_policy):
-        loop = asyncio.get_event_loop_policy().new_event_loop()
-        # Add a magic value to the event loop, so pytest-asyncio can determine if the
-        # event_loop fixture was overridden. Other implementations of event_loop don't
-        # set this value.
-        # The magic value must be set as part of the function definition, because pytest
-        # seems to have multiple instances of the same FixtureDef or fixture function
-        loop = _make_pytest_asyncio_loop(loop)
-        yield loop
-        loop.close()
-
-
-@pytest.fixture(scope="session")
-def _session_event_loop(
-    request: FixtureRequest, event_loop_policy: AbstractEventLoopPolicy
-) -> Iterator[asyncio.AbstractEventLoop]:
-    new_loop_policy = event_loop_policy
-    with _temporary_event_loop_policy(new_loop_policy):
-        loop = _make_pytest_asyncio_loop(asyncio.new_event_loop())
-        asyncio.set_event_loop(loop)
-        yield loop
-        loop.close()
+for scope in Scope:
+    globals()[f"_{scope.value}_scoped_runner"] = _create_scoped_runner_fixture(
+        scope.value
+    )
 
 
 @pytest.fixture(scope="session", autouse=True)
 def event_loop_policy() -> AbstractEventLoopPolicy:
     """Return an instance of the policy used to create asyncio event loops."""
-    return asyncio.get_event_loop_policy()
+    return _get_event_loop_policy()
 
 
 def is_async_test(item: Item) -> bool:
diff -pruN 0.25.1-1/tests/async_fixtures/test_async_fixtures_contextvars.py 1.1.0-2/tests/async_fixtures/test_async_fixtures_contextvars.py
--- 0.25.1-1/tests/async_fixtures/test_async_fixtures_contextvars.py	2025-01-02 04:58:42.000000000 +0000
+++ 1.1.0-2/tests/async_fixtures/test_async_fixtures_contextvars.py	2025-07-16 03:50:17.000000000 +0000
@@ -5,10 +5,8 @@ contextvars were not properly maintained
 
 from __future__ import annotations
 
-import sys
 from textwrap import dedent
 
-import pytest
 from pytest import Pytester
 
 _prelude = dedent(
@@ -56,11 +54,6 @@ def test_var_from_sync_generator_propaga
     result.assert_outcomes(passed=1)
 
 
-@pytest.mark.xfail(
-    sys.version_info < (3, 11),
-    reason="requires asyncio Task context support",
-    strict=True,
-)
 def test_var_from_async_generator_propagates_to_sync(pytester: Pytester):
     pytester.makeini("[pytest]\nasyncio_default_fixture_loop_scope = function")
     pytester.makepyfile(
@@ -86,11 +79,6 @@ def test_var_from_async_generator_propag
     result.assert_outcomes(passed=1)
 
 
-@pytest.mark.xfail(
-    sys.version_info < (3, 11),
-    reason="requires asyncio Task context support",
-    strict=True,
-)
 def test_var_from_async_fixture_propagates_to_sync(pytester: Pytester):
     pytester.makeini("[pytest]\nasyncio_default_fixture_loop_scope = function")
     pytester.makepyfile(
@@ -115,11 +103,6 @@ def test_var_from_async_fixture_propagat
     result.assert_outcomes(passed=1)
 
 
-@pytest.mark.xfail(
-    sys.version_info < (3, 11),
-    reason="requires asyncio Task context support",
-    strict=True,
-)
 def test_var_from_generator_reset_before_previous_fixture_cleanup(pytester: Pytester):
     pytester.makeini("[pytest]\nasyncio_default_fixture_loop_scope = function")
     pytester.makepyfile(
@@ -149,11 +132,6 @@ def test_var_from_generator_reset_before
     result.assert_outcomes(passed=1)
 
 
-@pytest.mark.xfail(
-    sys.version_info < (3, 11),
-    reason="requires asyncio Task context support",
-    strict=True,
-)
 def test_var_from_fixture_reset_before_previous_fixture_cleanup(pytester: Pytester):
     pytester.makeini("[pytest]\nasyncio_default_fixture_loop_scope = function")
     pytester.makepyfile(
@@ -183,11 +161,6 @@ def test_var_from_fixture_reset_before_p
     result.assert_outcomes(passed=1)
 
 
-@pytest.mark.xfail(
-    sys.version_info < (3, 11),
-    reason="requires asyncio Task context support",
-    strict=True,
-)
 def test_var_previous_value_restored_after_fixture(pytester: Pytester):
     pytester.makeini("[pytest]\nasyncio_default_fixture_loop_scope = function")
     pytester.makepyfile(
@@ -216,11 +189,6 @@ def test_var_previous_value_restored_aft
     result.assert_outcomes(passed=1)
 
 
-@pytest.mark.xfail(
-    sys.version_info < (3, 11),
-    reason="requires asyncio Task context support",
-    strict=True,
-)
 def test_var_set_to_existing_value_ok(pytester: Pytester):
     pytester.makeini("[pytest]\nasyncio_default_fixture_loop_scope = function")
     pytester.makepyfile(
diff -pruN 0.25.1-1/tests/async_fixtures/test_async_fixtures_scope.py 1.1.0-2/tests/async_fixtures/test_async_fixtures_scope.py
--- 0.25.1-1/tests/async_fixtures/test_async_fixtures_scope.py	2025-01-02 04:58:42.000000000 +0000
+++ 1.1.0-2/tests/async_fixtures/test_async_fixtures_scope.py	1970-01-01 00:00:00.000000000 +0000
@@ -1,30 +0,0 @@
-"""
-We support module-scoped async fixtures, but only if the event loop is
-module-scoped too.
-"""
-
-from __future__ import annotations
-
-import asyncio
-
-import pytest
-
-
-@pytest.fixture(scope="module")
-def event_loop():
-    """A module-scoped event loop."""
-    loop = asyncio.new_event_loop()
-    yield loop
-    loop.close()
-
-
-@pytest.fixture(scope="module")
-async def async_fixture():
-    await asyncio.sleep(0.1)
-    return 1
-
-
-@pytest.mark.asyncio
-async def test_async_fixture_scope(async_fixture):
-    assert async_fixture == 1
-    await asyncio.sleep(0.1)
diff -pruN 0.25.1-1/tests/async_fixtures/test_async_fixtures_with_finalizer.py 1.1.0-2/tests/async_fixtures/test_async_fixtures_with_finalizer.py
--- 0.25.1-1/tests/async_fixtures/test_async_fixtures_with_finalizer.py	2025-01-02 04:58:42.000000000 +0000
+++ 1.1.0-2/tests/async_fixtures/test_async_fixtures_with_finalizer.py	1970-01-01 00:00:00.000000000 +0000
@@ -1,63 +0,0 @@
-from __future__ import annotations
-
-import asyncio
-import functools
-
-import pytest
-
-import pytest_asyncio
-
-
-@pytest.mark.asyncio(loop_scope="module")
-async def test_module_with_event_loop_finalizer(port_with_event_loop_finalizer):
-    await asyncio.sleep(0.01)
-    assert port_with_event_loop_finalizer
-
-
-@pytest.mark.asyncio(loop_scope="module")
-async def test_module_with_get_event_loop_finalizer(port_with_get_event_loop_finalizer):
-    await asyncio.sleep(0.01)
-    assert port_with_get_event_loop_finalizer
-
-
-@pytest.fixture(scope="module")
-def event_loop():
-    """Change event_loop fixture to module level."""
-    policy = asyncio.get_event_loop_policy()
-    loop = policy.new_event_loop()
-    yield loop
-    loop.close()
-
-
-@pytest_asyncio.fixture(loop_scope="module", scope="module")
-async def port_with_event_loop_finalizer(request):
-    def port_finalizer(finalizer):
-        async def port_afinalizer():
-            # await task using loop provided by event_loop fixture
-            # RuntimeError is raised if task is created on a different loop
-            await finalizer
-
-        asyncio.run(port_afinalizer())
-
-    worker = asyncio.ensure_future(asyncio.sleep(0.2))
-    request.addfinalizer(functools.partial(port_finalizer, worker))
-    return True
-
-
-@pytest_asyncio.fixture(loop_scope="module", scope="module")
-async def port_with_get_event_loop_finalizer(request):
-    def port_finalizer(finalizer):
-        async def port_afinalizer():
-            # await task using current loop retrieved from the event loop policy
-            # RuntimeError is raised if task is created on a different loop.
-            # This can happen when pytest_fixture_setup
-            # does not set up the loop correctly,
-            # for example when policy.set_event_loop() is called with a wrong argument
-            await finalizer
-
-        current_loop = asyncio.get_event_loop_policy().get_event_loop()
-        current_loop.run_until_complete(port_afinalizer())
-
-    worker = asyncio.ensure_future(asyncio.sleep(0.2))
-    request.addfinalizer(functools.partial(port_finalizer, worker))
-    return True
diff -pruN 0.25.1-1/tests/async_fixtures/test_async_gen_fixtures.py 1.1.0-2/tests/async_fixtures/test_async_gen_fixtures.py
--- 0.25.1-1/tests/async_fixtures/test_async_gen_fixtures.py	2025-01-02 04:58:42.000000000 +0000
+++ 1.1.0-2/tests/async_fixtures/test_async_gen_fixtures.py	1970-01-01 00:00:00.000000000 +0000
@@ -1,53 +0,0 @@
-from __future__ import annotations
-
-import unittest.mock
-
-import pytest
-
-START = object()
-END = object()
-RETVAL = object()
-
-
-@pytest.fixture(scope="module")
-def mock():
-    return unittest.mock.Mock(return_value=RETVAL)
-
-
-@pytest.fixture
-async def async_gen_fixture(mock):
-    try:
-        yield mock(START)
-    except Exception as e:
-        mock(e)
-    else:
-        mock(END)
-
-
-@pytest.mark.asyncio
-async def test_async_gen_fixture(async_gen_fixture, mock):
-    assert mock.called
-    assert mock.call_args_list[-1] == unittest.mock.call(START)
-    assert async_gen_fixture is RETVAL
-
-
-@pytest.mark.asyncio
-async def test_async_gen_fixture_finalized(mock):
-    try:
-        assert mock.called
-        assert mock.call_args_list[-1] == unittest.mock.call(END)
-    finally:
-        mock.reset_mock()
-
-
-class TestAsyncGenFixtureMethod:
-    is_same_instance = False
-
-    @pytest.fixture(autouse=True)
-    async def async_gen_fixture_method(self):
-        self.is_same_instance = True
-        yield None
-
-    @pytest.mark.asyncio
-    async def test_async_gen_fixture_method(self):
-        assert self.is_same_instance
diff -pruN 0.25.1-1/tests/async_fixtures/test_parametrized_loop.py 1.1.0-2/tests/async_fixtures/test_parametrized_loop.py
--- 0.25.1-1/tests/async_fixtures/test_parametrized_loop.py	2025-01-02 04:58:42.000000000 +0000
+++ 1.1.0-2/tests/async_fixtures/test_parametrized_loop.py	1970-01-01 00:00:00.000000000 +0000
@@ -1,48 +0,0 @@
-from __future__ import annotations
-
-from textwrap import dedent
-
-from pytest import Pytester
-
-
-def test_event_loop_parametrization(pytester: Pytester):
-    pytester.makepyfile(
-        dedent(
-            """\
-            import asyncio
-
-            import pytest
-            import pytest_asyncio
-
-            TESTS_COUNT = 0
-
-
-            def teardown_module():
-                # parametrized 2 * 2 times: 2 for 'event_loop' and 2 for 'fix'
-                assert TESTS_COUNT == 4
-
-
-            @pytest.fixture(scope="module", params=[1, 2])
-            def event_loop(request):
-                request.param
-                loop = asyncio.new_event_loop()
-                yield loop
-                loop.close()
-
-
-            @pytest_asyncio.fixture(params=["a", "b"])
-            async def fix(request):
-                await asyncio.sleep(0)
-                return request.param
-
-
-            @pytest.mark.asyncio
-            async def test_parametrized_loop(fix):
-                await asyncio.sleep(0)
-                global TESTS_COUNT
-                TESTS_COUNT += 1
-            """
-        )
-    )
-    result = pytester.runpytest_subprocess("--asyncio-mode=strict")
-    result.assert_outcomes(passed=4)
diff -pruN 0.25.1-1/tests/conftest.py 1.1.0-2/tests/conftest.py
--- 0.25.1-1/tests/conftest.py	2025-01-02 04:58:42.000000000 +0000
+++ 1.1.0-2/tests/conftest.py	2025-07-16 03:50:17.000000000 +0000
@@ -1,34 +1,3 @@
 from __future__ import annotations
 
-import asyncio
-
-import pytest
-
 pytest_plugins = "pytester"
-
-
-@pytest.fixture
-def dependent_fixture(event_loop):
-    """A fixture dependent on the event_loop fixture, doing some cleanup."""
-    counter = 0
-
-    async def just_a_sleep():
-        """Just sleep a little while."""
-        nonlocal event_loop
-        await asyncio.sleep(0.1)
-        nonlocal counter
-        counter += 1
-
-    event_loop.run_until_complete(just_a_sleep())
-    yield
-    event_loop.run_until_complete(just_a_sleep())
-
-    assert counter == 2
-
-
-@pytest.fixture(scope="session", name="factory_involving_factories")
-def factory_involving_factories_fixture(unused_tcp_port_factory):
-    def factory():
-        return unused_tcp_port_factory()
-
-    return factory
diff -pruN 0.25.1-1/tests/hypothesis/test_base.py 1.1.0-2/tests/hypothesis/test_base.py
--- 0.25.1-1/tests/hypothesis/test_base.py	2025-01-02 04:58:42.000000000 +0000
+++ 1.1.0-2/tests/hypothesis/test_base.py	2025-07-16 03:50:17.000000000 +0000
@@ -45,43 +45,6 @@ async def test_mark_and_parametrize(x, y
     assert y in (1, 2)
 
 
-def test_can_use_explicit_event_loop_fixture(pytester: Pytester):
-    pytester.makeini("[pytest]\nasyncio_default_fixture_loop_scope = module")
-    pytester.makepyfile(
-        dedent(
-            """\
-            import asyncio
-            import pytest
-            from hypothesis import given
-            import hypothesis.strategies as st
-
-            pytest_plugins = 'pytest_asyncio'
-
-            @pytest.fixture(scope="module")
-            def event_loop():
-                loop = asyncio.get_event_loop_policy().new_event_loop()
-                yield loop
-                loop.close()
-
-            @given(st.integers())
-            @pytest.mark.asyncio
-            async def test_explicit_fixture_request(event_loop, n):
-                semaphore = asyncio.Semaphore(value=0)
-                event_loop.call_soon(semaphore.release)
-                await semaphore.acquire()
-            """
-        )
-    )
-    result = pytester.runpytest_subprocess("--asyncio-mode=strict", "-W default")
-    result.assert_outcomes(passed=1, warnings=2)
-    result.stdout.fnmatch_lines(
-        [
-            '*is asynchronous and explicitly requests the "event_loop" fixture*',
-            "*event_loop fixture provided by pytest-asyncio has been redefined*",
-        ]
-    )
-
-
 def test_async_auto_marked(pytester: Pytester):
     pytester.makeini("[pytest]\nasyncio_default_fixture_loop_scope = function")
     pytester.makepyfile(
diff -pruN 0.25.1-1/tests/loop_fixture_scope/conftest.py 1.1.0-2/tests/loop_fixture_scope/conftest.py
--- 0.25.1-1/tests/loop_fixture_scope/conftest.py	2025-01-02 04:58:42.000000000 +0000
+++ 1.1.0-2/tests/loop_fixture_scope/conftest.py	1970-01-01 00:00:00.000000000 +0000
@@ -1,17 +0,0 @@
-from __future__ import annotations
-
-import asyncio
-
-import pytest
-
-
-class CustomSelectorLoop(asyncio.SelectorEventLoop):
-    """A subclass with no overrides, just to test for presence."""
-
-
-@pytest.fixture(scope="module")
-def event_loop():
-    """Create an instance of the default event loop for each test case."""
-    loop = CustomSelectorLoop()
-    yield loop
-    loop.close()
diff -pruN 0.25.1-1/tests/loop_fixture_scope/test_loop_fixture_scope.py 1.1.0-2/tests/loop_fixture_scope/test_loop_fixture_scope.py
--- 0.25.1-1/tests/loop_fixture_scope/test_loop_fixture_scope.py	2025-01-02 04:58:42.000000000 +0000
+++ 1.1.0-2/tests/loop_fixture_scope/test_loop_fixture_scope.py	1970-01-01 00:00:00.000000000 +0000
@@ -1,19 +0,0 @@
-"""Unit tests for overriding the event loop with a larger scoped one."""
-
-from __future__ import annotations
-
-import asyncio
-
-import pytest
-
-
-@pytest.mark.asyncio
-async def test_for_custom_loop():
-    """This test should be executed using the custom loop."""
-    await asyncio.sleep(0.01)
-    assert type(asyncio.get_event_loop()).__name__ == "CustomSelectorLoop"
-
-
-@pytest.mark.asyncio
-async def test_dependent_fixture(dependent_fixture):
-    await asyncio.sleep(0.1)
diff -pruN 0.25.1-1/tests/markers/test_class_scope.py 1.1.0-2/tests/markers/test_class_scope.py
--- 0.25.1-1/tests/markers/test_class_scope.py	2025-01-02 04:58:42.000000000 +0000
+++ 1.1.0-2/tests/markers/test_class_scope.py	2025-07-16 03:50:17.000000000 +0000
@@ -82,29 +82,6 @@ def test_asyncio_mark_provides_class_sco
     result.assert_outcomes(passed=2)
 
 
-def test_asyncio_mark_raises_when_class_scoped_is_request_without_class(
-    pytester: pytest.Pytester,
-):
-    pytester.makeini("[pytest]\nasyncio_default_fixture_loop_scope = function")
-    pytester.makepyfile(
-        dedent(
-            """\
-            import asyncio
-            import pytest
-
-            @pytest.mark.asyncio(loop_scope="class")
-            async def test_has_no_surrounding_class():
-                pass
-            """
-        )
-    )
-    result = pytester.runpytest("--asyncio-mode=strict")
-    result.assert_outcomes(errors=1)
-    result.stdout.fnmatch_lines(
-        "*is marked to be run in an event loop with scope*",
-    )
-
-
 def test_asyncio_mark_is_inherited_to_subclasses(pytester: pytest.Pytester):
     pytester.makeini("[pytest]\nasyncio_default_fixture_loop_scope = function")
     pytester.makepyfile(
diff -pruN 0.25.1-1/tests/markers/test_function_scope.py 1.1.0-2/tests/markers/test_function_scope.py
--- 0.25.1-1/tests/markers/test_function_scope.py	2025-01-02 04:58:42.000000000 +0000
+++ 1.1.0-2/tests/markers/test_function_scope.py	2025-07-16 03:50:17.000000000 +0000
@@ -88,31 +88,8 @@ def test_warns_when_scope_argument_is_pr
         )
     )
     result = pytester.runpytest_subprocess("--asyncio-mode=strict")
-    result.assert_outcomes(passed=1, warnings=2)
-    result.stdout.fnmatch_lines("*DeprecationWarning*")
-
-
-def test_function_scope_supports_explicit_event_loop_fixture_request(
-    pytester: Pytester,
-):
-    pytester.makeini("[pytest]\nasyncio_default_fixture_loop_scope = function")
-    pytester.makepyfile(
-        dedent(
-            """\
-            import pytest
-
-            pytestmark = pytest.mark.asyncio
-
-            async def test_remember_loop(event_loop):
-                pass
-            """
-        )
-    )
-    result = pytester.runpytest_subprocess("--asyncio-mode=strict", "-W default")
     result.assert_outcomes(passed=1, warnings=1)
-    result.stdout.fnmatch_lines(
-        '*is asynchronous and explicitly requests the "event_loop" fixture*'
-    )
+    result.stdout.fnmatch_lines("*DeprecationWarning*")
 
 
 def test_asyncio_mark_respects_the_loop_policy(
diff -pruN 0.25.1-1/tests/markers/test_module_scope.py 1.1.0-2/tests/markers/test_module_scope.py
--- 0.25.1-1/tests/markers/test_module_scope.py	2025-01-02 04:58:42.000000000 +0000
+++ 1.1.0-2/tests/markers/test_module_scope.py	2025-07-16 03:50:17.000000000 +0000
@@ -5,59 +5,6 @@ from textwrap import dedent
 from pytest import Pytester
 
 
-def test_asyncio_mark_works_on_module_level(pytester: Pytester):
-    pytester.makeini("[pytest]\nasyncio_default_fixture_loop_scope = function")
-    pytester.makepyfile(
-        dedent(
-            """\
-            import asyncio
-
-            import pytest
-
-            pytestmark = pytest.mark.asyncio
-
-
-            class TestPyTestMark:
-                async def test_is_asyncio(self, event_loop, sample_fixture):
-                    assert asyncio.get_event_loop()
-
-                    counter = 1
-
-                    async def inc():
-                        nonlocal counter
-                        counter += 1
-                        await asyncio.sleep(0)
-
-                    await asyncio.ensure_future(inc())
-                    assert counter == 2
-
-
-            async def test_is_asyncio(event_loop, sample_fixture):
-                assert asyncio.get_event_loop()
-                counter = 1
-
-                async def inc():
-                    nonlocal counter
-                    counter += 1
-                    await asyncio.sleep(0)
-
-                await asyncio.ensure_future(inc())
-                assert counter == 2
-
-
-            @pytest.fixture
-            def sample_fixture():
-                return None
-            """
-        )
-    )
-    result = pytester.runpytest_subprocess("--asyncio-mode=strict", "-W default")
-    result.assert_outcomes(passed=2, warnings=2)
-    result.stdout.fnmatch_lines(
-        '*is asynchronous and explicitly requests the "event_loop" fixture*'
-    )
-
-
 def test_asyncio_mark_provides_module_scoped_loop_strict_mode(pytester: Pytester):
     pytester.makeini("[pytest]\nasyncio_default_fixture_loop_scope = function")
     pytester.makepyfile(
@@ -89,28 +36,6 @@ def test_asyncio_mark_provides_module_sc
     result.assert_outcomes(passed=3)
 
 
-def test_raise_when_event_loop_fixture_is_requested_in_addition_to_scoped_loop(
-    pytester: Pytester,
-):
-    pytester.makeini("[pytest]\nasyncio_default_fixture_loop_scope = function")
-    pytester.makepyfile(
-        dedent(
-            """\
-            import asyncio
-            import pytest
-
-            pytestmark = pytest.mark.asyncio(loop_scope="module")
-
-            async def test_remember_loop(event_loop):
-                pass
-            """
-        )
-    )
-    result = pytester.runpytest("--asyncio-mode=strict")
-    result.assert_outcomes(errors=1)
-    result.stdout.fnmatch_lines("*MultipleEventLoopsRequestedError: *")
-
-
 def test_asyncio_mark_respects_the_loop_policy(
     pytester: Pytester,
 ):
diff -pruN 0.25.1-1/tests/markers/test_package_scope.py 1.1.0-2/tests/markers/test_package_scope.py
--- 0.25.1-1/tests/markers/test_package_scope.py	2025-01-02 04:58:42.000000000 +0000
+++ 1.1.0-2/tests/markers/test_package_scope.py	2025-07-16 03:50:17.000000000 +0000
@@ -69,28 +69,6 @@ def test_asyncio_mark_provides_package_s
     result.assert_outcomes(passed=4)
 
 
-def test_raise_when_event_loop_fixture_is_requested_in_addition_to_scoped_loop(
-    pytester: Pytester,
-):
-    pytester.makeini("[pytest]\nasyncio_default_fixture_loop_scope = function")
-    pytester.makepyfile(
-        __init__="",
-        test_raises=dedent(
-            """\
-            import asyncio
-            import pytest
-
-            @pytest.mark.asyncio(loop_scope="package")
-            async def test_remember_loop(event_loop):
-                pass
-            """
-        ),
-    )
-    result = pytester.runpytest("--asyncio-mode=strict")
-    result.assert_outcomes(errors=1)
-    result.stdout.fnmatch_lines("*MultipleEventLoopsRequestedError: *")
-
-
 def test_asyncio_mark_respects_the_loop_policy(
     pytester: Pytester,
 ):
@@ -361,23 +339,3 @@ def test_asyncio_mark_handles_missing_ev
     )
     result = pytester.runpytest("--asyncio-mode=strict")
     result.assert_outcomes(passed=2)
-
-
-def test_standalone_test_does_not_trigger_warning_about_no_current_event_loop_being_set(
-    pytester: Pytester,
-):
-    pytester.makeini("[pytest]\nasyncio_default_fixture_loop_scope = function")
-    pytester.makepyfile(
-        __init__="",
-        test_module=dedent(
-            """\
-            import pytest
-
-            @pytest.mark.asyncio(loop_scope="package")
-            async def test_anything():
-                pass
-            """
-        ),
-    )
-    result = pytester.runpytest_subprocess("--asyncio-mode=strict")
-    result.assert_outcomes(warnings=0, passed=1)
diff -pruN 0.25.1-1/tests/markers/test_session_scope.py 1.1.0-2/tests/markers/test_session_scope.py
--- 0.25.1-1/tests/markers/test_session_scope.py	2025-01-02 04:58:42.000000000 +0000
+++ 1.1.0-2/tests/markers/test_session_scope.py	2025-07-16 03:50:17.000000000 +0000
@@ -70,28 +70,6 @@ def test_asyncio_mark_provides_session_s
     result.assert_outcomes(passed=4)
 
 
-def test_raise_when_event_loop_fixture_is_requested_in_addition_to_scoped_loop(
-    pytester: Pytester,
-):
-    pytester.makeini("[pytest]\nasyncio_default_fixture_loop_scope = function")
-    pytester.makepyfile(
-        __init__="",
-        test_raises=dedent(
-            """\
-            import asyncio
-            import pytest
-
-            @pytest.mark.asyncio(loop_scope="session")
-            async def test_remember_loop(event_loop):
-                pass
-            """
-        ),
-    )
-    result = pytester.runpytest("--asyncio-mode=strict")
-    result.assert_outcomes(errors=1)
-    result.stdout.fnmatch_lines("*MultipleEventLoopsRequestedError: *")
-
-
 def test_asyncio_mark_respects_the_loop_policy(
     pytester: Pytester,
 ):
diff -pruN 0.25.1-1/tests/modes/test_strict_mode.py 1.1.0-2/tests/modes/test_strict_mode.py
--- 0.25.1-1/tests/modes/test_strict_mode.py	2025-01-02 04:58:42.000000000 +0000
+++ 1.1.0-2/tests/modes/test_strict_mode.py	2025-07-16 03:50:17.000000000 +0000
@@ -2,7 +2,7 @@ from __future__ import annotations
 
 from textwrap import dedent
 
-from pytest import Pytester
+from pytest import Pytester, version_tuple as pytest_version
 
 
 def test_strict_mode_cmdline(pytester: Pytester):
@@ -95,7 +95,10 @@ def test_strict_mode_ignores_unmarked_co
         )
     )
     result = pytester.runpytest_subprocess("--asyncio-mode=strict", "-W default")
-    result.assert_outcomes(skipped=1, warnings=1)
+    if pytest_version >= (8, 4, 0):
+        result.assert_outcomes(failed=1, skipped=0, warnings=0)
+    else:
+        result.assert_outcomes(skipped=1, warnings=1)
     result.stdout.fnmatch_lines(["*async def functions are not natively supported*"])
 
 
@@ -117,7 +120,11 @@ def test_strict_mode_ignores_unmarked_fi
         )
     )
     result = pytester.runpytest_subprocess("--asyncio-mode=strict", "-W default")
-    result.assert_outcomes(skipped=1, warnings=2)
+
+    if pytest_version >= (8, 4, 0):
+        result.assert_outcomes(failed=1, skipped=0, warnings=2)
+    else:
+        result.assert_outcomes(skipped=1, warnings=2)
     result.stdout.fnmatch_lines(
         [
             "*async def functions are not natively supported*",
@@ -149,7 +156,10 @@ def test_strict_mode_marked_test_unmarke
         )
     )
     result = pytester.runpytest_subprocess("--asyncio-mode=strict", "-W default")
-    result.assert_outcomes(passed=1, failed=0, skipped=0, warnings=1)
+    if pytest_version >= (8, 4, 0):
+        result.assert_outcomes(passed=1, failed=0, skipped=0, warnings=2)
+    else:
+        result.assert_outcomes(passed=1, failed=0, skipped=0, warnings=1)
     result.stdout.fnmatch_lines(
         [
             "*warnings summary*",
@@ -193,7 +203,10 @@ def test_strict_mode_marked_test_unmarke
         )
     )
     result = pytester.runpytest_subprocess("--asyncio-mode=strict", "-W default")
-    result.assert_outcomes(passed=1, warnings=1)
+    if pytest_version >= (8, 4, 0):
+        result.assert_outcomes(passed=1, warnings=2)
+    else:
+        result.assert_outcomes(passed=1, warnings=1)
     result.stdout.fnmatch_lines(
         [
             "*warnings summary*",
diff -pruN 0.25.1-1/tests/test_asyncio_mark.py 1.1.0-2/tests/test_asyncio_mark.py
--- 0.25.1-1/tests/test_asyncio_mark.py	2025-01-02 04:58:42.000000000 +0000
+++ 1.1.0-2/tests/test_asyncio_mark.py	2025-07-16 03:50:17.000000000 +0000
@@ -146,3 +146,80 @@ def test_asyncio_mark_on_async_generator
     result.stdout.fnmatch_lines(
         ["*Tests based on asynchronous generators are not supported*"]
     )
+
+
+def test_asyncio_marker_fallbacks_to_configured_default_loop_scope_if_not_set(
+    pytester: Pytester,
+):
+    pytester.makeini(
+        dedent(
+            """\
+            [pytest]
+            asyncio_default_fixture_loop_scope = function
+            asyncio_default_test_loop_scope = session
+            """
+        )
+    )
+
+    pytester.makepyfile(
+        dedent(
+            """\
+            import asyncio
+            import pytest_asyncio
+            import pytest
+
+            loop: asyncio.AbstractEventLoop
+
+            @pytest_asyncio.fixture(loop_scope="session", scope="session")
+            async def session_loop_fixture():
+                global loop
+                loop = asyncio.get_running_loop()
+
+            async def test_a(session_loop_fixture):
+                global loop
+                assert asyncio.get_running_loop() is loop
+            """
+        )
+    )
+
+    result = pytester.runpytest("--asyncio-mode=auto")
+    result.assert_outcomes(passed=1)
+
+
+def test_asyncio_marker_uses_marker_loop_scope_even_if_config_is_set(
+    pytester: Pytester,
+):
+    pytester.makeini(
+        dedent(
+            """\
+            [pytest]
+            asyncio_default_fixture_loop_scope = function
+            asyncio_default_test_loop_scope = module
+            """
+        )
+    )
+
+    pytester.makepyfile(
+        dedent(
+            """\
+            import asyncio
+            import pytest_asyncio
+            import pytest
+
+            loop: asyncio.AbstractEventLoop
+
+            @pytest_asyncio.fixture(loop_scope="session", scope="session")
+            async def session_loop_fixture():
+                global loop
+                loop = asyncio.get_running_loop()
+
+            @pytest.mark.asyncio(loop_scope="session")
+            async def test_a(session_loop_fixture):
+                global loop
+                assert asyncio.get_running_loop() is loop
+            """
+        )
+    )
+
+    result = pytester.runpytest("--asyncio-mode=auto")
+    result.assert_outcomes(passed=1)
diff -pruN 0.25.1-1/tests/test_dependent_fixtures.py 1.1.0-2/tests/test_dependent_fixtures.py
--- 0.25.1-1/tests/test_dependent_fixtures.py	2025-01-02 04:58:42.000000000 +0000
+++ 1.1.0-2/tests/test_dependent_fixtures.py	1970-01-01 00:00:00.000000000 +0000
@@ -1,16 +0,0 @@
-from __future__ import annotations
-
-import asyncio
-
-import pytest
-
-
-@pytest.mark.asyncio
-async def test_dependent_fixture(dependent_fixture):
-    """Test a dependent fixture."""
-    await asyncio.sleep(0.1)
-
-
-@pytest.mark.asyncio
-async def test_factory_involving_factories(factory_involving_factories):
-    factory_involving_factories()
diff -pruN 0.25.1-1/tests/test_event_loop_fixture.py 1.1.0-2/tests/test_event_loop_fixture.py
--- 0.25.1-1/tests/test_event_loop_fixture.py	2025-01-02 04:58:42.000000000 +0000
+++ 1.1.0-2/tests/test_event_loop_fixture.py	2025-07-16 03:50:17.000000000 +0000
@@ -53,3 +53,91 @@ def test_event_loop_fixture_respects_eve
     )
     result = pytester.runpytest_subprocess("--asyncio-mode=strict")
     result.assert_outcomes(passed=2)
+
+
+def test_event_loop_fixture_handles_unclosed_async_gen(
+    pytester: Pytester,
+):
+    pytester.makeini("[pytest]\nasyncio_default_fixture_loop_scope = function")
+    pytester.makepyfile(
+        dedent(
+            """\
+            import asyncio
+            import pytest
+
+            pytest_plugins = 'pytest_asyncio'
+
+            @pytest.mark.asyncio
+            async def test_something():
+                async def generator_fn():
+                    yield
+                    yield
+
+                gen = generator_fn()
+                await gen.__anext__()
+            """
+        )
+    )
+    result = pytester.runpytest_subprocess("--asyncio-mode=strict", "-W", "default")
+    result.assert_outcomes(passed=1, warnings=0)
+
+
+def test_closing_event_loop_in_sync_fixture_teardown_raises_warning(
+    pytester: Pytester,
+):
+    pytester.makeini("[pytest]\nasyncio_default_fixture_loop_scope = function")
+    pytester.makepyfile(
+        dedent(
+            """\
+            import asyncio
+            import pytest
+            import pytest_asyncio
+            pytest_plugins = 'pytest_asyncio'
+
+            @pytest_asyncio.fixture
+            async def _event_loop():
+                return asyncio.get_running_loop()
+
+            @pytest.fixture
+            def close_event_loop(_event_loop):
+                yield
+                # fixture has its own cleanup code
+                _event_loop.close()
+
+            @pytest.mark.asyncio
+            async def test_something(close_event_loop):
+                await asyncio.sleep(0.01)
+            """
+        )
+    )
+    result = pytester.runpytest_subprocess("--asyncio-mode=strict")
+    result.assert_outcomes(passed=1, warnings=1)
+    result.stdout.fnmatch_lines(
+        ["*An exception occurred during teardown of an asyncio.Runner*"]
+    )
+
+
+def test_event_loop_fixture_asyncgen_error(
+    pytester: Pytester,
+):
+    pytester.makeini("[pytest]\nasyncio_default_fixture_loop_scope = function")
+    pytester.makepyfile(
+        dedent(
+            """\
+            import asyncio
+            import pytest
+
+            pytest_plugins = 'pytest_asyncio'
+
+            @pytest.mark.asyncio
+            async def test_something():
+                # mock shutdown_asyncgen failure
+                loop = asyncio.get_running_loop()
+                async def fail():
+                    raise RuntimeError("mock error cleaning up...")
+                loop.shutdown_asyncgens = fail
+            """
+        )
+    )
+    result = pytester.runpytest_subprocess("--asyncio-mode=strict", "-W", "default")
+    result.assert_outcomes(passed=1, warnings=1)
diff -pruN 0.25.1-1/tests/test_event_loop_fixture_finalizer.py 1.1.0-2/tests/test_event_loop_fixture_finalizer.py
--- 0.25.1-1/tests/test_event_loop_fixture_finalizer.py	2025-01-02 04:58:42.000000000 +0000
+++ 1.1.0-2/tests/test_event_loop_fixture_finalizer.py	1970-01-01 00:00:00.000000000 +0000
@@ -1,149 +0,0 @@
-from __future__ import annotations
-
-from textwrap import dedent
-
-from pytest import Pytester
-
-
-def test_event_loop_fixture_finalizer_returns_fresh_loop_after_test(pytester: Pytester):
-    pytester.makeini("[pytest]\nasyncio_default_fixture_loop_scope = function")
-    pytester.makepyfile(
-        dedent(
-            """\
-            import asyncio
-
-            import pytest
-
-            loop = asyncio.new_event_loop()
-            asyncio.set_event_loop(loop)
-
-            @pytest.mark.asyncio
-            async def test_1():
-                # This async test runs in its own event loop
-                global loop
-                running_loop = asyncio.get_event_loop_policy().get_event_loop()
-                # Make sure this test case received a different loop
-                assert running_loop is not loop
-
-            def test_2():
-                # Code outside of pytest-asyncio should not receive a "used" event loop
-                current_loop = asyncio.get_event_loop_policy().get_event_loop()
-                assert not current_loop.is_running()
-                assert not current_loop.is_closed()
-            """
-        )
-    )
-    result = pytester.runpytest("--asyncio-mode=strict")
-    result.assert_outcomes(passed=2)
-
-
-def test_event_loop_fixture_finalizer_handles_loop_set_to_none_sync(
-    pytester: Pytester,
-):
-    pytester.makeini("[pytest]\nasyncio_default_fixture_loop_scope = function")
-    pytester.makepyfile(
-        dedent(
-            """\
-            import asyncio
-
-            def test_sync(event_loop):
-                asyncio.get_event_loop_policy().set_event_loop(None)
-            """
-        )
-    )
-    result = pytester.runpytest("--asyncio-mode=strict")
-    result.assert_outcomes(passed=1)
-
-
-def test_event_loop_fixture_finalizer_handles_loop_set_to_none_async_without_fixture(
-    pytester: Pytester,
-):
-    pytester.makeini("[pytest]\nasyncio_default_fixture_loop_scope = function")
-    pytester.makepyfile(
-        dedent(
-            """\
-            import asyncio
-            import pytest
-
-            @pytest.mark.asyncio
-            async def test_async_without_explicit_fixture_request():
-                asyncio.get_event_loop_policy().set_event_loop(None)
-            """
-        )
-    )
-    result = pytester.runpytest("--asyncio-mode=strict")
-    result.assert_outcomes(passed=1)
-
-
-def test_event_loop_fixture_finalizer_handles_loop_set_to_none_async_with_fixture(
-    pytester: Pytester,
-):
-    pytester.makeini("[pytest]\nasyncio_default_fixture_loop_scope = function")
-    pytester.makepyfile(
-        dedent(
-            """\
-            import asyncio
-            import pytest
-
-            @pytest.mark.asyncio
-            async def test_async_with_explicit_fixture_request(event_loop):
-                asyncio.get_event_loop_policy().set_event_loop(None)
-            """
-        )
-    )
-    result = pytester.runpytest_subprocess("--asyncio-mode=strict", "-W default")
-    result.assert_outcomes(passed=1, warnings=1)
-    result.stdout.fnmatch_lines(
-        '*is asynchronous and explicitly requests the "event_loop" fixture*'
-    )
-
-
-def test_event_loop_fixture_finalizer_raises_warning_when_fixture_leaves_loop_unclosed(
-    pytester: Pytester,
-):
-    pytester.makeini("[pytest]\nasyncio_default_fixture_loop_scope = function")
-    pytester.makepyfile(
-        dedent(
-            """\
-            import asyncio
-            import pytest
-
-            pytest_plugins = 'pytest_asyncio'
-
-            @pytest.fixture
-            def event_loop():
-                loop = asyncio.get_event_loop_policy().new_event_loop()
-                yield loop
-
-            @pytest.mark.asyncio
-            async def test_ends_with_unclosed_loop():
-                pass
-            """
-        )
-    )
-    result = pytester.runpytest_subprocess("--asyncio-mode=strict", "-W", "default")
-    result.assert_outcomes(passed=1, warnings=2)
-    result.stdout.fnmatch_lines("*unclosed event loop*")
-
-
-def test_event_loop_fixture_finalizer_raises_warning_when_test_leaves_loop_unclosed(
-    pytester: Pytester,
-):
-    pytester.makeini("[pytest]\nasyncio_default_fixture_loop_scope = function")
-    pytester.makepyfile(
-        dedent(
-            """\
-            import asyncio
-            import pytest
-
-            pytest_plugins = 'pytest_asyncio'
-
-            @pytest.mark.asyncio
-            async def test_ends_with_unclosed_loop():
-                asyncio.set_event_loop(asyncio.new_event_loop())
-            """
-        )
-    )
-    result = pytester.runpytest_subprocess("--asyncio-mode=strict", "-W", "default")
-    result.assert_outcomes(passed=1, warnings=1)
-    result.stdout.fnmatch_lines("*unclosed event loop*")
diff -pruN 0.25.1-1/tests/test_event_loop_fixture_override_deprecation.py 1.1.0-2/tests/test_event_loop_fixture_override_deprecation.py
--- 0.25.1-1/tests/test_event_loop_fixture_override_deprecation.py	2025-01-02 04:58:42.000000000 +0000
+++ 1.1.0-2/tests/test_event_loop_fixture_override_deprecation.py	1970-01-01 00:00:00.000000000 +0000
@@ -1,113 +0,0 @@
-from __future__ import annotations
-
-from textwrap import dedent
-
-from pytest import Pytester
-
-
-def test_emit_warning_when_event_loop_fixture_is_redefined(pytester: Pytester):
-    pytester.makepyfile(
-        dedent(
-            """\
-            import asyncio
-            import pytest
-
-            @pytest.fixture
-            def event_loop():
-                loop = asyncio.new_event_loop()
-                yield loop
-                loop.close()
-
-            @pytest.mark.asyncio
-            async def test_emits_warning():
-                pass
-            """
-        )
-    )
-    result = pytester.runpytest_subprocess("--asyncio-mode=strict", "-W default")
-    result.assert_outcomes(passed=1, warnings=1)
-    result.stdout.fnmatch_lines(
-        ["*event_loop fixture provided by pytest-asyncio has been redefined*"]
-    )
-
-
-def test_emit_warning_when_event_loop_fixture_is_redefined_explicit_request(
-    pytester: Pytester,
-):
-    pytester.makepyfile(
-        dedent(
-            """\
-            import asyncio
-            import pytest
-
-            @pytest.fixture
-            def event_loop():
-                loop = asyncio.new_event_loop()
-                yield loop
-                loop.close()
-
-            @pytest.mark.asyncio
-            async def test_emits_warning_when_requested_explicitly(event_loop):
-                pass
-            """
-        )
-    )
-    result = pytester.runpytest_subprocess("--asyncio-mode=strict", "-W default")
-    result.assert_outcomes(passed=1, warnings=2)
-    result.stdout.fnmatch_lines(
-        ["*event_loop fixture provided by pytest-asyncio has been redefined*"]
-    )
-    result.stdout.fnmatch_lines(
-        ['*is asynchronous and explicitly requests the "event_loop" fixture*']
-    )
-
-
-def test_does_not_emit_warning_when_no_test_uses_the_event_loop_fixture(
-    pytester: Pytester,
-):
-    pytester.makepyfile(
-        dedent(
-            """\
-            import asyncio
-            import pytest
-
-            @pytest.fixture
-            def event_loop():
-                loop = asyncio.new_event_loop()
-                yield loop
-                loop.close()
-
-            def test_emits_no_warning():
-                pass
-            """
-        )
-    )
-    result = pytester.runpytest_subprocess("--asyncio-mode=strict")
-    result.assert_outcomes(passed=1, warnings=0)
-
-
-def test_emit_warning_when_redefined_event_loop_is_used_by_fixture(pytester: Pytester):
-    pytester.makepyfile(
-        dedent(
-            """\
-            import asyncio
-            import pytest
-            import pytest_asyncio
-
-            @pytest.fixture
-            def event_loop():
-                loop = asyncio.new_event_loop()
-                yield loop
-                loop.close()
-
-            @pytest_asyncio.fixture
-            async def uses_event_loop():
-                pass
-
-            def test_emits_warning(uses_event_loop):
-                pass
-            """
-        )
-    )
-    result = pytester.runpytest_subprocess("--asyncio-mode=strict", "-W default")
-    result.assert_outcomes(passed=1, warnings=1)
diff -pruN 0.25.1-1/tests/test_explicit_event_loop_fixture_request.py 1.1.0-2/tests/test_explicit_event_loop_fixture_request.py
--- 0.25.1-1/tests/test_explicit_event_loop_fixture_request.py	2025-01-02 04:58:42.000000000 +0000
+++ 1.1.0-2/tests/test_explicit_event_loop_fixture_request.py	1970-01-01 00:00:00.000000000 +0000
@@ -1,168 +0,0 @@
-from __future__ import annotations
-
-from textwrap import dedent
-
-from pytest import Pytester
-
-
-def test_emit_warning_when_event_loop_is_explicitly_requested_in_coroutine(
-    pytester: Pytester,
-):
-    pytester.makeini("[pytest]\nasyncio_default_fixture_loop_scope = function")
-    pytester.makepyfile(
-        dedent(
-            """\
-            import pytest
-
-            @pytest.mark.asyncio
-            async def test_coroutine_emits_warning(event_loop):
-                pass
-            """
-        )
-    )
-    result = pytester.runpytest_subprocess("--asyncio-mode=strict", "-W default")
-    result.assert_outcomes(passed=1, warnings=1)
-    result.stdout.fnmatch_lines(
-        ['*is asynchronous and explicitly requests the "event_loop" fixture*']
-    )
-
-
-def test_emit_warning_when_event_loop_is_explicitly_requested_in_coroutine_method(
-    pytester: Pytester,
-):
-    pytester.makeini("[pytest]\nasyncio_default_fixture_loop_scope = function")
-    pytester.makepyfile(
-        dedent(
-            """\
-            import pytest
-
-            class TestEmitsWarning:
-                @pytest.mark.asyncio
-                async def test_coroutine_emits_warning(self, event_loop):
-                    pass
-            """
-        )
-    )
-    result = pytester.runpytest_subprocess("--asyncio-mode=strict", "-W default")
-    result.assert_outcomes(passed=1, warnings=1)
-    result.stdout.fnmatch_lines(
-        ['*is asynchronous and explicitly requests the "event_loop" fixture*']
-    )
-
-
-def test_emit_warning_when_event_loop_is_explicitly_requested_in_coroutine_staticmethod(
-    pytester: Pytester,
-):
-    pytester.makeini("[pytest]\nasyncio_default_fixture_loop_scope = function")
-    pytester.makepyfile(
-        dedent(
-            """\
-            import pytest
-
-            class TestEmitsWarning:
-                @staticmethod
-                @pytest.mark.asyncio
-                async def test_coroutine_emits_warning(event_loop):
-                    pass
-            """
-        )
-    )
-    result = pytester.runpytest_subprocess("--asyncio-mode=strict", "-W default")
-    result.assert_outcomes(passed=1, warnings=1)
-    result.stdout.fnmatch_lines(
-        ['*is asynchronous and explicitly requests the "event_loop" fixture*']
-    )
-
-
-def test_emit_warning_when_event_loop_is_explicitly_requested_in_coroutine_fixture(
-    pytester: Pytester,
-):
-    pytester.makeini("[pytest]\nasyncio_default_fixture_loop_scope = function")
-    pytester.makepyfile(
-        dedent(
-            """\
-            import pytest
-            import pytest_asyncio
-
-            @pytest_asyncio.fixture
-            async def emits_warning(event_loop):
-                pass
-
-            @pytest.mark.asyncio
-            async def test_uses_fixture(emits_warning):
-                pass
-            """
-        )
-    )
-    result = pytester.runpytest_subprocess("--asyncio-mode=strict", "-W default")
-    result.assert_outcomes(passed=1, warnings=1)
-    result.stdout.fnmatch_lines(
-        ['*is asynchronous and explicitly requests the "event_loop" fixture*']
-    )
-
-
-def test_emit_warning_when_event_loop_is_explicitly_requested_in_async_gen_fixture(
-    pytester: Pytester,
-):
-    pytester.makeini("[pytest]\nasyncio_default_fixture_loop_scope = function")
-    pytester.makepyfile(
-        dedent(
-            """\
-            import pytest
-            import pytest_asyncio
-
-            @pytest_asyncio.fixture
-            async def emits_warning(event_loop):
-                yield
-
-            @pytest.mark.asyncio
-            async def test_uses_fixture(emits_warning):
-                pass
-            """
-        )
-    )
-    result = pytester.runpytest_subprocess("--asyncio-mode=strict", "-W default")
-    result.assert_outcomes(passed=1, warnings=1)
-    result.stdout.fnmatch_lines(
-        ['*is asynchronous and explicitly requests the "event_loop" fixture*']
-    )
-
-
-def test_does_not_emit_warning_when_event_loop_is_explicitly_requested_in_sync_function(
-    pytester: Pytester,
-):
-    pytester.makeini("[pytest]\nasyncio_default_fixture_loop_scope = function")
-    pytester.makepyfile(
-        dedent(
-            """\
-            import pytest
-
-            def test_uses_fixture(event_loop):
-                pass
-            """
-        )
-    )
-    result = pytester.runpytest("--asyncio-mode=strict")
-    result.assert_outcomes(passed=1)
-
-
-def test_does_not_emit_warning_when_event_loop_is_explicitly_requested_in_sync_fixture(
-    pytester: Pytester,
-):
-    pytester.makeini("[pytest]\nasyncio_default_fixture_loop_scope = function")
-    pytester.makepyfile(
-        dedent(
-            """\
-            import pytest
-
-            @pytest.fixture
-            def any_fixture(event_loop):
-                pass
-
-            def test_uses_fixture(any_fixture):
-                pass
-            """
-        )
-    )
-    result = pytester.runpytest("--asyncio-mode=strict")
-    result.assert_outcomes(passed=1)
diff -pruN 0.25.1-1/tests/test_multiloop.py 1.1.0-2/tests/test_multiloop.py
--- 0.25.1-1/tests/test_multiloop.py	2025-01-02 04:58:42.000000000 +0000
+++ 1.1.0-2/tests/test_multiloop.py	1970-01-01 00:00:00.000000000 +0000
@@ -1,72 +0,0 @@
-from __future__ import annotations
-
-from textwrap import dedent
-
-from pytest import Pytester
-
-
-def test_event_loop_override(pytester: Pytester):
-    pytester.makeconftest(
-        dedent(
-            '''\
-            import asyncio
-
-            import pytest
-
-
-            @pytest.fixture
-            def dependent_fixture(event_loop):
-                """A fixture dependent on the event_loop fixture, doing some cleanup."""
-                counter = 0
-
-                async def just_a_sleep():
-                    """Just sleep a little while."""
-                    nonlocal event_loop
-                    await asyncio.sleep(0.1)
-                    nonlocal counter
-                    counter += 1
-
-                event_loop.run_until_complete(just_a_sleep())
-                yield
-                event_loop.run_until_complete(just_a_sleep())
-
-                assert counter == 2
-
-
-            class CustomSelectorLoop(asyncio.SelectorEventLoop):
-                """A subclass with no overrides, just to test for presence."""
-
-
-            @pytest.fixture
-            def event_loop():
-                """Create an instance of the default event loop for each test case."""
-                loop = CustomSelectorLoop()
-                yield loop
-                loop.close()
-            '''
-        )
-    )
-    pytester.makepyfile(
-        dedent(
-            '''\
-            """Unit tests for overriding the event loop."""
-            import asyncio
-
-            import pytest
-
-
-            @pytest.mark.asyncio
-            async def test_for_custom_loop():
-                """This test should be executed using the custom loop."""
-                await asyncio.sleep(0.01)
-                assert type(asyncio.get_event_loop()).__name__ == "CustomSelectorLoop"
-
-
-            @pytest.mark.asyncio
-            async def test_dependent_fixture(dependent_fixture):
-                await asyncio.sleep(0.1)
-            '''
-        )
-    )
-    result = pytester.runpytest_subprocess("--asyncio-mode=strict")
-    result.assert_outcomes(passed=2, warnings=2)
diff -pruN 0.25.1-1/tests/test_simple.py 1.1.0-2/tests/test_simple.py
--- 0.25.1-1/tests/test_simple.py	2025-01-02 04:58:42.000000000 +0000
+++ 1.1.0-2/tests/test_simple.py	2025-07-16 03:50:17.000000000 +0000
@@ -14,13 +14,6 @@ async def async_coro():
     return "ok"
 
 
-def test_event_loop_fixture(event_loop):
-    """Test the injection of the event_loop fixture."""
-    assert event_loop
-    ret = event_loop.run_until_complete(async_coro())
-    assert ret == "ok"
-
-
 @pytest.mark.asyncio
 async def test_asyncio_marker():
     """Test the asyncio pytest marker."""
diff -pruN 0.25.1-1/tests/test_subprocess.py 1.1.0-2/tests/test_subprocess.py
--- 0.25.1-1/tests/test_subprocess.py	2025-01-02 04:58:42.000000000 +0000
+++ 1.1.0-2/tests/test_subprocess.py	2025-07-16 03:50:17.000000000 +0000
@@ -7,16 +7,6 @@ import sys
 
 import pytest
 
-if sys.platform == "win32":
-    # The default asyncio event loop implementation on Windows does not
-    # support subprocesses. Subprocesses are available for Windows if a
-    # ProactorEventLoop is used.
-    @pytest.fixture()
-    def event_loop():
-        loop = asyncio.ProactorEventLoop()
-        yield loop
-        loop.close()
-
 
 @pytest.mark.asyncio
 async def test_subprocess():
diff -pruN 0.25.1-1/tests/test_task_cleanup.py 1.1.0-2/tests/test_task_cleanup.py
--- 0.25.1-1/tests/test_task_cleanup.py	1970-01-01 00:00:00.000000000 +0000
+++ 1.1.0-2/tests/test_task_cleanup.py	2025-07-16 03:50:17.000000000 +0000
@@ -0,0 +1,30 @@
+from __future__ import annotations
+
+from textwrap import dedent
+
+from pytest import Pytester
+
+
+def test_task_is_cancelled_when_abandoned_by_test(pytester: Pytester):
+    pytester.makeini("[pytest]\nasyncio_default_fixture_loop_scope = function")
+    pytester.makepyfile(
+        dedent(
+            """\
+        import asyncio
+        import pytest
+
+        @pytest.mark.asyncio
+        async def test_create_task():
+            async def coroutine():
+                try:
+                    while True:
+                        await asyncio.sleep(0)
+                finally:
+                    raise RuntimeError("The task should be cancelled at this point.")
+
+            asyncio.create_task(coroutine())
+        """
+        )
+    )
+    result = pytester.runpytest("--asyncio-mode=strict")
+    result.assert_outcomes(passed=1)
diff -pruN 0.25.1-1/tox.ini 1.1.0-2/tox.ini
--- 0.25.1-1/tox.ini	2025-01-02 04:58:42.000000000 +0000
+++ 1.1.0-2/tox.ini	2025-07-16 03:50:17.000000000 +0000
@@ -1,6 +1,6 @@
 [tox]
 minversion = 4.9.0
-envlist = py39, py310, py311, py312, py313, pytest-min, docs
+envlist = py39, py310, py311, py312, py313, py314, pytest-min, docs
 isolated_build = true
 passenv =
     CI
@@ -76,4 +76,5 @@ python =
     3.11: py311
     3.12: py312
     3.13: py313
+    3.14-dev: py314
     pypy3: pypy3
