diff -pruN 1.1.0-2/.github/dependabot.yml 1.2.0-1/.github/dependabot.yml
--- 1.1.0-2/.github/dependabot.yml	2025-07-16 03:50:17.000000000 +0000
+++ 1.2.0-1/.github/dependabot.yml	2025-09-12 07:21:22.000000000 +0000
@@ -2,13 +2,7 @@
 version: 2
 updates:
 - package-ecosystem: pip
-  directory: /dependencies/default
-  schedule:
-    interval: weekly
-  open-pull-requests-limit: 10
-  target-branch: main
-- package-ecosystem: pip
-  directory: /dependencies/docs
+  directory: /
   schedule:
     interval: weekly
   open-pull-requests-limit: 10
diff -pruN 1.1.0-2/.github/workflows/main.yml 1.2.0-1/.github/workflows/main.yml
--- 1.1.0-2/.github/workflows/main.yml	2025-07-16 03:50:17.000000000 +0000
+++ 1.2.0-1/.github/workflows/main.yml	2025-09-12 07:21:22.000000000 +0000
@@ -16,37 +16,26 @@ env:
   PYTHON_LATEST: 3.13
 
 jobs:
-  lint:
-    name: Run linters
+  build:
+    name: Build package
     runs-on: ubuntu-latest
     outputs:
       version: ${{ steps.version.outputs.version }}
       prerelease: ${{ steps.version.outputs.prerelease }}
     steps:
-    - uses: actions/checkout@v4
+    - uses: actions/checkout@v5
       with:
         fetch-depth: 0
         persist-credentials: false
-    - uses: actions/setup-python@v5
+    - uses: actions/setup-python@v6
       with:
         python-version: ${{ env.PYTHON_LATEST }}
-    - name: Install GitHub matcher for ActionLint checker
-      run: |
-        echo "::add-matcher::.github/actionlint-matcher.json"
-    - name: Install pre-commit
-      run: python -m pip install pre-commit
-    - name: Run pre-commit checks
-      run: pre-commit run --all-files --show-diff-on-failure
-    - name: Install check-wheel-content, and twine
-      run: python -m pip install build check-wheel-contents twine
-    - name: Build package
-      run: python -m build
+    - name: Install tox
+      run: python -m pip install tox
+    - name: Build package and check distributions
+      run: tox run -e build
     - name: List result
       run: ls -l dist
-    - name: Check wheel contents
-      run: check-wheel-contents dist/*.whl
-    - name: Check long_description
-      run: python -m twine check dist/*
     - name: Install pytest-asyncio
       run: pip install .
     - name: Get version info
@@ -58,6 +47,25 @@ jobs:
         name: dist
         path: dist
 
+  lint:
+    name: Run linters
+    runs-on: ubuntu-latest
+    steps:
+    - uses: actions/checkout@v5
+      with:
+        fetch-depth: 0
+        persist-credentials: false
+    - uses: actions/setup-python@v6
+      with:
+        python-version: ${{ env.PYTHON_LATEST }}
+    - name: Install GitHub matcher for ActionLint checker
+      run: |
+        echo "::add-matcher::.github/actionlint-matcher.json"
+    - name: Install pre-commit
+      run: python -m pip install pre-commit
+    - name: Run pre-commit checks
+      run: pre-commit run --all-files --show-diff-on-failure
+
   test:
     name: ${{ matrix.os }} - Python ${{ matrix.python-version }}
     runs-on: ${{ matrix.os }}-latest
@@ -77,10 +85,10 @@ jobs:
 
 
     steps:
-    - uses: actions/checkout@v4
+    - uses: actions/checkout@v5
       with:
         persist-credentials: false
-    - uses: actions/setup-python@v5
+    - uses: actions/setup-python@v6
       with:
         python-version: ${{ matrix.python-version }}
     - name: Install dependencies
@@ -109,17 +117,17 @@ jobs:
   check:
     name: Check
     if: always()
-    needs: [lint, test]
+    needs: [build, lint, test]
     runs-on: ubuntu-latest
     steps:
     - name: Decide whether the needed jobs succeeded or failed
       uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe  # v1.2.2
       with:
         jobs: ${{ toJSON(needs) }}
-    - uses: actions/checkout@v4
+    - uses: actions/checkout@v5
       with:
         persist-credentials: false
-    - uses: actions/setup-python@v5
+    - uses: actions/setup-python@v6
       with:
         python-version: ${{ env.PYTHON_LATEST }}
     - name: Install Coverage.py
@@ -127,7 +135,7 @@ jobs:
         set -xe
         python -m pip install --upgrade coverage[toml]
     - name: Download coverage data for all test runs
-      uses: actions/download-artifact@v4
+      uses: actions/download-artifact@v5
       with:
         pattern: coverage-*
         path: coverage
@@ -137,7 +145,7 @@ jobs:
         coverage combine
         coverage xml
     - name: Upload coverage report
-      uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24  # v5.4.3
+      uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7  # v5.5.1
       with:
         files: coverage.xml
         fail_ci_if_error: true
@@ -145,18 +153,18 @@ jobs:
 
   create-github-release:
     name: Create GitHub release
-    needs: [lint, check]
+    needs: [build, lint, check]
     runs-on: ubuntu-latest
     permissions:
       contents: write
     steps:
     - name: Checkout
-      uses: actions/checkout@v4
+      uses: actions/checkout@v5
       with:
         fetch-depth: 0
         persist-credentials: false
     - name: Install Python
-      uses: actions/setup-python@v5
+      uses: actions/setup-python@v6
     - name: Install towncrier
       run: pip install towncrier==24.8.0
     - name: Install pandoc
@@ -168,53 +176,57 @@ jobs:
       if: ${{ !contains(github.ref, 'refs/tags/') }}
       run: towncrier build --draft --version "${version}" > release-notes.rst
       env:
-        version: ${{ needs.lint.outputs.version }}
+        version: ${{ needs.build.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
+        # Strip signature from signed tags
+        sed -i -e "/-----BEGIN PGP SIGNATURE-----/,/-----END PGP SIGNATURE-----\n/d" \
+          -e "/-----BEGIN SSH SIGNATURE-----/,/-----END SSH SIGNATURE-----\n/d" release-notes.rst
     - name: Convert Release Notes to Markdown
       run: |
-        pandoc -s -o release-notes.md release-notes.rst
+        pandoc --wrap=preserve -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
+      uses: actions/download-artifact@v5
       with:
         name: dist
         path: dist
     - name: Create GitHub Release
       if: github.event_name == 'push' && contains(github.ref, 'refs/tags/')
-      uses: ncipollo/release-action@bcfe5470707e8832e12347755757cec0eb3c22af  # v1.18.0
+      uses: ncipollo/release-action@b7eabc95ff50cbeeedec83973935c8f306dfcd0b  # v1.20.0
       with:
-        name: pytest-asyncio ${{ needs.lint.outputs.version }}
+        name: pytest-asyncio ${{ needs.build.outputs.version }}
         artifacts: dist/*
         bodyFile: release-notes.md
-        prerelease: ${{ needs.lint.outputs.prerelease }}
+        prerelease: ${{ needs.build.outputs.prerelease }}
         token: ${{ secrets.GITHUB_TOKEN }}
+        allowUpdates: true
+        draft: true
+        skipIfReleaseExists: true
 
   publish-test-pypi:
     name: Publish packages to test.pypi.org
     if: github.event_name == 'push' && github.ref == 'refs/heads/main'
-    needs: [lint, check]
+    needs: [build, lint, check, create-github-release]
     runs-on: ubuntu-latest
     permissions:
       id-token: write
     steps:
     - name: Download distributions
-      uses: actions/download-artifact@v4
+      uses: actions/download-artifact@v5
       with:
         name: dist
         path: dist
     - name: Upload to test.pypi.org
-      uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc  # v1.12.4
+      uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e  # v1.13.0
       with:
         repository-url: https://test.pypi.org/legacy/
 
@@ -222,13 +234,13 @@ jobs:
     name: Publish packages to pypi.org
     environment: release
     if: github.event_name == 'push' && contains(github.ref, 'refs/tags/')
-    needs: [lint, check]
+    needs: [build, lint, check, create-github-release]
     runs-on: ubuntu-latest
     permissions:
       id-token: write
     steps:
     - name: Download distributions
-      uses: actions/download-artifact@v4
+      uses: actions/download-artifact@v5
       with:
         name: dist
         path: dist
@@ -236,4 +248,4 @@ jobs:
       run: |
         tree dist
     - name: PyPI upload
-      uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc  # v1.12.4
+      uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e  # v1.13.0
diff -pruN 1.1.0-2/.gitignore 1.2.0-1/.gitignore
--- 1.1.0-2/.gitignore	2025-07-16 03:50:17.000000000 +0000
+++ 1.2.0-1/.gitignore	2025-09-12 07:21:22.000000000 +0000
@@ -62,7 +62,3 @@ target/
 
 # pyenv
 .python-version
-
-
-# generated by setuptools_scm
-pytest_asyncio/_version.py
diff -pruN 1.1.0-2/.pre-commit-config.yaml 1.2.0-1/.pre-commit-config.yaml
--- 1.1.0-2/.pre-commit-config.yaml	2025-07-16 03:50:17.000000000 +0000
+++ 1.2.0-1/.pre-commit-config.yaml	2025-09-12 07:21:22.000000000 +0000
@@ -1,15 +1,26 @@
 ---
 repos:
 - repo: https://github.com/pre-commit/pre-commit-hooks
-  rev: v5.0.0
+  rev: v6.0.0
   hooks:
+  - id: trailing-whitespace
+  - id: end-of-file-fixer
   - id: check-merge-conflict
     exclude: rst$
+  - id: check-case-conflict
+  - id: check-json
+  - id: check-xml
+  - id: check-yaml
+  - id: debug-statements
 - repo: https://github.com/astral-sh/ruff-pre-commit
-  rev: v0.12.3
+  rev: v0.12.12
   hooks:
   - id: ruff
     args: [--fix]
+- repo: https://github.com/asottile/pyupgrade
+  rev: v3.20.0
+  hooks:
+  - id: pyupgrade
 - repo: https://github.com/asottile/yesqa
   rev: v1.5.0
   hooks:
@@ -29,20 +40,8 @@ repos:
   hooks:
   - id: yamlfmt
     args: [--mapping, '2', --sequence, '2', --offset, '0']
-- repo: https://github.com/pre-commit/pre-commit-hooks
-  rev: v5.0.0
-  hooks:
-  - id: trailing-whitespace
-  - id: end-of-file-fixer
-  - id: fix-encoding-pragma
-    args: [--remove]
-  - id: check-case-conflict
-  - id: check-json
-  - id: check-xml
-  - id: check-yaml
-  - id: debug-statements
 - repo: https://github.com/pre-commit/mirrors-mypy
-  rev: v1.16.1
+  rev: v1.17.1
   hooks:
   - id: mypy
     exclude: ^(docs|tests)/.*
@@ -65,7 +64,7 @@ repos:
     - 'SC1004:'
     stages: [manual]
 - repo: https://github.com/sirosen/check-jsonschema
-  rev: 0.33.2
+  rev: 0.33.3
   hooks:
   - id: check-github-actions
 - repo: https://github.com/tox-dev/pyproject-fmt
@@ -73,9 +72,9 @@ repos:
   hooks:
   - id: pyproject-fmt
       # https://pyproject-fmt.readthedocs.io/en/latest/#calculating-max-supported-python-version
-    additional_dependencies: [tox>=4.9]
+    additional_dependencies: [tox>=4.28]
 - repo: https://github.com/zizmorcore/zizmor-pre-commit
-  rev: v1.11.0
+  rev: v1.12.1
   hooks:
   - id: zizmor
 ci:
diff -pruN 1.1.0-2/constraints.txt 1.2.0-1/constraints.txt
--- 1.1.0-2/constraints.txt	1970-01-01 00:00:00.000000000 +0000
+++ 1.2.0-1/constraints.txt	2025-09-12 07:21:22.000000000 +0000
@@ -0,0 +1,66 @@
+alabaster==0.7.16
+annotated-types-0.7.0
+attrs==25.3.0
+babel==2.17.0
+backports.asyncio.runner==1.2.0
+backports.tarfile==1.2.0
+certifi==2025.8.3
+charset-normalizer==3.4.3
+check-wheel-contents==0.6.1
+cffi==1.17.1
+click==8.1.8
+coverage==7.10.6
+cryptography==45.0.7
+docutils==0.21.2
+exceptiongroup==1.3.0
+hypothesis==6.138.15
+iniconfig==2.1.0
+id==1.5.0
+idna==3.10
+imagesize==1.4.1
+importlib_metadata==8.7.0
+iniconfig==2.1.0
+jaraco.classes==3.4.0
+jaraco.context==6.0.1
+jaraco.functools==4.3.0
+jeepney==0.9.0
+Jinja2==3.1.6
+keyring==25.6.0
+markdown-it-py==3.0.0
+MarkupSafe==3.0.2
+mdurl==0.1.2
+more-itertools==10.8.0
+nh3==0.3.0
+packaging==25.0
+pluggy==1.6.0
+Pygments==2.19.2
+pycparser==2.22
+pydantic==2.11.7
+pydantic-core==2.33.2
+pytest==8.4.2
+readme-renderer==44.0
+requests==2.32.5
+requests-toolbelt==1.0.0
+rfc3986==2.0.0
+rich==14.1.0
+SecretStorage==3.3.3
+setuptools==80.9.0
+setuptools-scm==9.2.0
+snowballstemmer==3.0.1
+sortedcontainers==2.4.0
+Sphinx==8.0.2
+sphinx-rtd-theme==3.0.2
+sphinxcontrib-applehelp==2.0.0
+sphinxcontrib-devhelp==2.0.0
+sphinxcontrib-htmlhelp==2.1.0
+sphinxcontrib-jquery==4.1
+sphinxcontrib-jsmath==1.0.1
+sphinxcontrib-qthelp==2.0.0
+sphinxcontrib-serializinghtml==2.0.0
+tomli==2.2.1
+twine==6.2.0
+typing_extensions==4.15.0
+typing-inspection==0.4.1
+urllib3==2.5.0
+wheel-filename==1.4.2
+zipp==3.23.0
diff -pruN 1.1.0-2/debian/changelog 1.2.0-1/debian/changelog
--- 1.1.0-2/debian/changelog	2025-09-16 12:02:45.000000000 +0000
+++ 1.2.0-1/debian/changelog	2025-10-19 21:34:41.000000000 +0000
@@ -1,3 +1,11 @@
+python-pytest-asyncio (1.2.0-1) unstable; urgency=medium
+
+  * Team upload.
+  * New upstream release.
+  * Standards-Version: 4.7.2.
+
+ -- Colin Watson <cjwatson@debian.org>  Sun, 19 Oct 2025 22:34:41 +0100
+
 python-pytest-asyncio (1.1.0-2) unstable; urgency=medium
 
   * Team upload.
diff -pruN 1.1.0-2/debian/control 1.2.0-1/debian/control
--- 1.1.0-2/debian/control	2025-09-16 12:01:37.000000000 +0000
+++ 1.2.0-1/debian/control	2025-10-19 21:34:37.000000000 +0000
@@ -16,7 +16,7 @@ Build-Depends:
  python3-pytest-trio <!nocheck>,
  python3-setuptools,
  python3-setuptools-scm,
-Standards-Version: 4.6.1
+Standards-Version: 4.7.2
 Vcs-Git: https://salsa.debian.org/python-team/packages/pytest-asyncio.git
 Vcs-Browser: https://salsa.debian.org/python-team/packages/pytest-asyncio
 Homepage: https://github.com/pytest-dev/pytest-asyncio
diff -pruN 1.1.0-2/dependencies/default/constraints.txt 1.2.0-1/dependencies/default/constraints.txt
--- 1.1.0-2/dependencies/default/constraints.txt	2025-07-16 03:50:17.000000000 +0000
+++ 1.2.0-1/dependencies/default/constraints.txt	1970-01-01 00:00:00.000000000 +0000
@@ -1,11 +0,0 @@
-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.14.1
diff -pruN 1.1.0-2/dependencies/default/requirements.txt 1.2.0-1/dependencies/default/requirements.txt
--- 1.1.0-2/dependencies/default/requirements.txt	2025-07-16 03:50:17.000000000 +0000
+++ 1.2.0-1/dependencies/default/requirements.txt	1970-01-01 00:00:00.000000000 +0000
@@ -1,3 +0,0 @@
-# Always adjust install_requires in setup.cfg and pytest-min-requirements.txt
-# when changing runtime dependencies
-pytest >= 8.2,<9
diff -pruN 1.1.0-2/dependencies/docs/constraints.txt 1.2.0-1/dependencies/docs/constraints.txt
--- 1.1.0-2/dependencies/docs/constraints.txt	2025-07-16 03:50:17.000000000 +0000
+++ 1.2.0-1/dependencies/docs/constraints.txt	2025-09-12 07:21:22.000000000 +0000
@@ -1,7 +1,7 @@
 alabaster==0.7.16
 Babel==2.17.0
-certifi==2025.7.14
-charset-normalizer==3.4.2
+certifi==2025.8.3
+charset-normalizer==3.4.3
 docutils==0.21.2
 idna==3.10
 imagesize==1.4.1
@@ -9,7 +9,7 @@ Jinja2==3.1.6
 MarkupSafe==3.0.2
 packaging==25.0
 Pygments==2.19.2
-requests==2.32.4
+requests==2.32.5
 snowballstemmer==3.0.1
 Sphinx==8.0.2
 sphinx-rtd-theme==3.0.2
diff -pruN 1.1.0-2/dependencies/docs/requirements.txt 1.2.0-1/dependencies/docs/requirements.txt
--- 1.1.0-2/dependencies/docs/requirements.txt	2025-07-16 03:50:17.000000000 +0000
+++ 1.2.0-1/dependencies/docs/requirements.txt	1970-01-01 00:00:00.000000000 +0000
@@ -1,2 +0,0 @@
-sphinx >= 5.3
-sphinx-rtd-theme >= 1.0
diff -pruN 1.1.0-2/docs/concepts.rst 1.2.0-1/docs/concepts.rst
--- 1.1.0-2/docs/concepts.rst	2025-07-16 03:50:17.000000000 +0000
+++ 1.2.0-1/docs/concepts.rst	2025-09-12 07:21:22.000000000 +0000
@@ -71,3 +71,15 @@ In *auto* mode pytest-asyncio automatica
 This mode is intended for projects that use *asyncio* as their only asynchronous programming library. Auto mode makes for the simplest test and fixture configuration and is the recommended default.
 
 If you intend to support multiple asynchronous programming libraries, e.g. *asyncio* and *trio*, strict mode will be the preferred option.
+
+.. _concepts/concurrent_execution:
+
+Test execution and concurrency
+==============================
+
+pytest-asyncio runs async tests sequentially, just like how pytest runs synchronous tests. Each asynchronous test runs within its assigned event loop. For example, consider the following two tests:
+
+.. include:: concepts_concurrent_execution_example.py
+    :code: python
+
+This sequential execution is intentional and important for maintaining test isolation. Running tests concurrently could introduce race conditions and side effects where one test could interfere with another, making test results unreliable and difficult to debug.
diff -pruN 1.1.0-2/docs/concepts_concurrent_execution_example.py 1.2.0-1/docs/concepts_concurrent_execution_example.py
--- 1.1.0-2/docs/concepts_concurrent_execution_example.py	1970-01-01 00:00:00.000000000 +0000
+++ 1.2.0-1/docs/concepts_concurrent_execution_example.py	2025-09-12 07:21:22.000000000 +0000
@@ -0,0 +1,16 @@
+import asyncio
+
+import pytest
+
+
+@pytest.mark.asyncio
+async def test_first():
+    await asyncio.sleep(2)  # Takes 2 seconds
+
+
+@pytest.mark.asyncio
+async def test_second():
+    await asyncio.sleep(2)  # Takes 2 seconds
+
+
+# Total execution time: ~4 seconds, not ~2 seconds
diff -pruN 1.1.0-2/docs/how-to-guides/index.rst 1.2.0-1/docs/how-to-guides/index.rst
--- 1.1.0-2/docs/how-to-guides/index.rst	2025-07-16 03:50:17.000000000 +0000
+++ 1.2.0-1/docs/how-to-guides/index.rst	2025-09-12 07:21:22.000000000 +0000
@@ -14,6 +14,7 @@ How-To Guides
   run_module_tests_in_same_loop
   run_package_tests_in_same_loop
   multiple_loops
+  parametrize_with_asyncio
   uvloop
   test_item_is_async
 
diff -pruN 1.1.0-2/docs/how-to-guides/parametrize_with_asyncio.rst 1.2.0-1/docs/how-to-guides/parametrize_with_asyncio.rst
--- 1.1.0-2/docs/how-to-guides/parametrize_with_asyncio.rst	1970-01-01 00:00:00.000000000 +0000
+++ 1.2.0-1/docs/how-to-guides/parametrize_with_asyncio.rst	2025-09-12 07:21:22.000000000 +0000
@@ -0,0 +1,11 @@
+=====================================
+How to parametrize asynchronous tests
+=====================================
+
+The ``pytest.mark.parametrize`` marker works with asynchronous tests the same as with synchronous tests. You can apply both ``pytest.mark.asyncio`` and ``pytest.mark.parametrize`` to asynchronous test functions:
+
+.. include:: parametrize_with_asyncio_example.py
+    :code: python
+
+.. note::
+   Whilst asynchronous tests can be parametrized, each individual test case still runs sequentially, not concurrently. For more information about how pytest-asyncio executes tests, see :ref:`concepts/concurrent_execution`.
diff -pruN 1.1.0-2/docs/how-to-guides/parametrize_with_asyncio_example.py 1.2.0-1/docs/how-to-guides/parametrize_with_asyncio_example.py
--- 1.1.0-2/docs/how-to-guides/parametrize_with_asyncio_example.py	1970-01-01 00:00:00.000000000 +0000
+++ 1.2.0-1/docs/how-to-guides/parametrize_with_asyncio_example.py	2025-09-12 07:21:22.000000000 +0000
@@ -0,0 +1,10 @@
+import asyncio
+
+import pytest
+
+
+@pytest.mark.asyncio
+@pytest.mark.parametrize("value", [1, 2, 3])
+async def test_parametrized_async_function(value):
+    await asyncio.sleep(1)
+    assert value > 0
diff -pruN 1.1.0-2/docs/reference/changelog.rst 1.2.0-1/docs/reference/changelog.rst
--- 1.1.0-2/docs/reference/changelog.rst	2025-07-16 03:50:17.000000000 +0000
+++ 1.2.0-1/docs/reference/changelog.rst	2025-09-12 07:21:22.000000000 +0000
@@ -10,6 +10,31 @@ This project uses `towncrier <https://to
 
 .. towncrier release notes start
 
+`1.2.0 <https://github.com/pytest-dev/pytest-asyncio/tree/1.2.0>`_ - 2025-09-12
+===============================================================================
+
+Added
+-----
+
+- ``--asyncio-debug`` CLI option and ``asyncio_debug`` configuration option to enable asyncio debug mode for the default event loop. (`#980 <https://github.com/pytest-dev/pytest-asyncio/issues/980>`_)
+- A ``pytest.UsageError`` for invalid configuration values of ``asyncio_default_fixture_loop_scope`` and ``asyncio_default_test_loop_scope``. (`#1189 <https://github.com/pytest-dev/pytest-asyncio/issues/1189>`_)
+- Compatibility with the `Pyright` type checker (`#731 <https://github.com/pytest-dev/pytest-asyncio/issues/731>`_)
+
+
+Fixed
+-----
+
+- ``RuntimeError: There is no current event loop in thread 'MainThread'`` when any test unsets the event loop (such as when using ``asyncio.run`` and ``asyncio.Runner``). (`#1177 <https://github.com/pytest-dev/pytest-asyncio/issues/1177>`_)
+- Deprecation warning when decorating an asynchronous fixture with ``@pytest.fixture`` in `strict` mode. The warning message now refers to the correct package. (`#1198 <https://github.com/pytest-dev/pytest-asyncio/issues/1198>`_)
+
+
+Notes for Downstream Packagers
+------------------------------
+
+- Bump the minimum required version of tox to v4.28. This change is only relevant if you use the ``tox.ini`` file provided by pytest-asyncio to run tests.
+- Extend dependency on typing-extensions>=4.12 from Python<3.10 to Python<3.13.
+
+
 `1.1.0 <https://github.com/pytest-dev/pytest-asyncio/tree/1.1.0>`_ - 2025-07-16
 ===============================================================================
 
@@ -96,7 +121,7 @@ Notes for Downstream Packagers
 
 0.25.0 (2024-12-13)
 ===================
-- Deprecated: Added warning when asyncio test requests async ``@pytest.fixture`` in strict mode. This will become an error in a future version of flake8-asyncio. `#979 <https://github.com/pytest-dev/pytest-asyncio/pull/979>`_
+- Deprecated: Added warning when asyncio test requests async ``@pytest.fixture`` in strict mode. This will become an error in a future version of pytest-asyncio. `#979 <https://github.com/pytest-dev/pytest-asyncio/pull/979>`_
 - Updates the error message about `pytest.mark.asyncio`'s `scope` keyword argument to say `loop_scope` instead. `#1004 <https://github.com/pytest-dev/pytest-asyncio/pull/1004>`_
 - Verbose log displays correct parameter name: asyncio_default_fixture_loop_scope `#990 <https://github.com/pytest-dev/pytest-asyncio/pull/990>`_
 - 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>`_
diff -pruN 1.1.0-2/docs/reference/configuration.rst 1.2.0-1/docs/reference/configuration.rst
--- 1.1.0-2/docs/reference/configuration.rst	2025-07-16 03:50:17.000000000 +0000
+++ 1.2.0-1/docs/reference/configuration.rst	2025-09-12 07:21:22.000000000 +0000
@@ -14,6 +14,29 @@ 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``
 
+.. _configuration/asyncio_debug:
+
+asyncio_debug
+=============
+Enables `asyncio debug mode <https://docs.python.org/3/library/asyncio-dev.html#debug-mode>`_ for the default event loop used by asynchronous tests and fixtures.
+
+The debug mode can be set by the ``asyncio_debug`` configuration option in the `configuration file
+<https://docs.pytest.org/en/latest/reference/customize.html>`_:
+
+.. code-block:: ini
+
+   # pytest.ini
+   [pytest]
+   asyncio_debug = true
+
+The value can also be set via the ``--asyncio-debug`` command-line option:
+
+.. code-block:: bash
+
+   $ pytest tests --asyncio-debug
+
+By default, asyncio debug mode is disabled.
+
 asyncio_mode
 ============
 The pytest-asyncio mode can be set by the ``asyncio_mode`` configuration option in the `configuration file
diff -pruN 1.1.0-2/pyproject.toml 1.2.0-1/pyproject.toml
--- 1.1.0-2/pyproject.toml	2025-07-16 03:50:17.000000000 +0000
+++ 1.2.0-1/pyproject.toml	2025-09-12 07:21:22.000000000 +0000
@@ -43,7 +43,7 @@ dynamic = [
 dependencies = [
   "backports-asyncio-runner>=1.1,<2; python_version<'3.11'",
   "pytest>=8.2,<9",
-  "typing-extensions>=4.12; python_version<'3.10'",
+  "typing-extensions>=4.12; python_version<'3.13'",
 ]
 optional-dependencies.docs = [
   "sphinx>=5.3",
@@ -67,7 +67,6 @@ packages = [
 include-package-data = true
 
 [tool.setuptools_scm]
-write_to = "pytest_asyncio/_version.py"
 local_scheme = "no-local-version"
 
 [tool.ruff]
@@ -138,9 +137,6 @@ source = [
 ]
 branch = true
 data_file = "coverage/coverage"
-omit = [
-  "*/_version.py",
-]
 parallel = true
 
 [tool.coverage.report]
diff -pruN 1.1.0-2/pytest_asyncio/__init__.py 1.2.0-1/pytest_asyncio/__init__.py
--- 1.1.0-2/pytest_asyncio/__init__.py	2025-07-16 03:50:17.000000000 +0000
+++ 1.2.0-1/pytest_asyncio/__init__.py	2025-09-12 07:21:22.000000000 +0000
@@ -2,7 +2,10 @@
 
 from __future__ import annotations
 
-from ._version import version as __version__  # noqa: F401
+from importlib.metadata import version
+
 from .plugin import fixture, is_async_test
 
+__version__ = version(__name__)
+
 __all__ = ("fixture", "is_async_test")
diff -pruN 1.1.0-2/pytest_asyncio/plugin.py 1.2.0-1/pytest_asyncio/plugin.py
--- 1.1.0-2/pytest_asyncio/plugin.py	2025-07-16 03:50:17.000000000 +0000
+++ 1.2.0-1/pytest_asyncio/plugin.py	2025-09-12 07:21:22.000000000 +0000
@@ -59,6 +59,11 @@ if sys.version_info >= (3, 11):
 else:
     from backports.asyncio.runner import Runner
 
+if sys.version_info >= (3, 13):
+    from typing import TypeIs
+else:
+    from typing_extensions import TypeIs
+
 _ScopeName = Literal["session", "package", "module", "class", "function"]
 _R = TypeVar("_R", bound=Union[Awaitable[Any], AsyncIterator[Any]])
 _P = ParamSpec("_P")
@@ -91,12 +96,25 @@ def pytest_addoption(parser: Parser, plu
         metavar="MODE",
         help=ASYNCIO_MODE_HELP,
     )
+    group.addoption(
+        "--asyncio-debug",
+        dest="asyncio_debug",
+        action="store_true",
+        default=None,
+        help="enable asyncio debug mode for the default event loop",
+    )
     parser.addini(
         "asyncio_mode",
         help="default value for --asyncio-mode",
         default="strict",
     )
     parser.addini(
+        "asyncio_debug",
+        help="enable asyncio debug mode for the default event loop",
+        type="bool",
+        default="false",
+    )
+    parser.addini(
         "asyncio_default_fixture_loop_scope",
         type="string",
         help="default scope of the asyncio event loop used to execute async fixtures",
@@ -195,6 +213,17 @@ def _get_asyncio_mode(config: Config) ->
         ) from e
 
 
+def _get_asyncio_debug(config: Config) -> bool:
+    val = config.getoption("asyncio_debug")
+    if val is None:
+        val = config.getini("asyncio_debug")
+
+    if isinstance(val, bool):
+        return val
+    else:
+        return val == "true"
+
+
 _DEFAULT_FIXTURE_LOOP_SCOPE_UNSET = """\
 The configuration option "asyncio_default_fixture_loop_scope" is unset.
 The event loop scope for asynchronous fixtures will default to the fixture caching \
@@ -205,10 +234,25 @@ avoid unexpected behavior in the future.
 """
 
 
+def _validate_scope(scope: str | None, option_name: str) -> None:
+    if scope is None:
+        return
+    valid_scopes = [s.value for s in Scope]
+    if scope not in valid_scopes:
+        raise pytest.UsageError(
+            f"{scope!r} is not a valid {option_name}. "
+            f"Valid scopes are: {', '.join(valid_scopes)}."
+        )
+
+
 def pytest_configure(config: Config) -> None:
-    default_loop_scope = config.getini("asyncio_default_fixture_loop_scope")
-    if not default_loop_scope:
+    default_fixture_loop_scope = config.getini("asyncio_default_fixture_loop_scope")
+    _validate_scope(default_fixture_loop_scope, "asyncio_default_fixture_loop_scope")
+    if not default_fixture_loop_scope:
         warnings.warn(PytestDeprecationWarning(_DEFAULT_FIXTURE_LOOP_SCOPE_UNSET))
+
+    default_test_loop_scope = config.getini("asyncio_default_test_loop_scope")
+    _validate_scope(default_test_loop_scope, "asyncio_default_test_loop_scope")
     config.addinivalue_line(
         "markers",
         "asyncio: "
@@ -221,10 +265,12 @@ def pytest_configure(config: Config) ->
 def pytest_report_header(config: Config) -> list[str]:
     """Add asyncio config to pytest header."""
     mode = _get_asyncio_mode(config)
+    debug = _get_asyncio_debug(config)
     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"debug={debug}",
         f"asyncio_default_fixture_loop_scope={default_fixture_loop_scope}",
         f"asyncio_default_test_loop_scope={default_test_loop_scope}",
     ]
@@ -265,7 +311,7 @@ def _wrap_asyncgen_fixture(
         gen_obj = fixture_function(*args, **kwargs)
 
         async def setup():
-            res = await gen_obj.__anext__()  # type: ignore[union-attr]
+            res = await gen_obj.__anext__()
             return res
 
         context = contextvars.copy_context()
@@ -278,7 +324,7 @@ def _wrap_asyncgen_fixture(
 
             async def async_finalizer() -> None:
                 try:
-                    await gen_obj.__anext__()  # type: ignore[union-attr]
+                    await gen_obj.__anext__()
                 except StopAsyncIteration:
                     pass
                 else:
@@ -307,8 +353,7 @@ def _wrap_async_fixture(
     runner: Runner,
     request: FixtureRequest,
 ) -> Callable[AsyncFixtureParams, AsyncFixtureReturnType]:
-
-    @functools.wraps(fixture_function)  # type: ignore[arg-type]
+    @functools.wraps(fixture_function)
     def _async_fixture_wrapper(
         *args: AsyncFixtureParams.args,
         **kwargs: AsyncFixtureParams.kwargs,
@@ -392,6 +437,7 @@ class PytestAsyncioFunction(Function):
         Function item.
         """
         assert function.get_closest_marker("asyncio")
+        assert function.parent is not None
         subclass_instance = cls.from_parent(
             function.parent,
             name=function.name,
@@ -410,6 +456,49 @@ class PytestAsyncioFunction(Function):
         """Returns whether the specified function can be replaced by this class"""
         raise NotImplementedError()
 
+    def setup(self) -> None:
+        runner_fixture_id = f"_{self._loop_scope}_scoped_runner"
+        if runner_fixture_id not in self.fixturenames:
+            self.fixturenames.append(runner_fixture_id)
+        return super().setup()
+
+    def runtest(self) -> None:
+        runner_fixture_id = f"_{self._loop_scope}_scoped_runner"
+        runner = self._request.getfixturevalue(runner_fixture_id)
+        context = contextvars.copy_context()
+        synchronized_obj = _synchronize_coroutine(
+            getattr(*self._synchronization_target_attr), runner, context
+        )
+        with MonkeyPatch.context() as c:
+            c.setattr(*self._synchronization_target_attr, synchronized_obj)
+            super().runtest()
+
+    @functools.cached_property
+    def _loop_scope(self) -> _ScopeName:
+        """
+        Return the scope of the asyncio event loop this item is run in.
+
+        The effective scope is determined lazily. It is identical to to the
+        `loop_scope` value of the closest `asyncio` pytest marker. If no such
+        marker is present, the the loop scope is determined by the configuration
+        value of `asyncio_default_test_loop_scope`, instead.
+        """
+        marker = self.get_closest_marker("asyncio")
+        assert marker is not None
+        default_loop_scope = _get_default_test_loop_scope(self.config)
+        return _get_marked_loop_scope(marker, default_loop_scope)
+
+    @property
+    def _synchronization_target_attr(self) -> tuple[object, str]:
+        """
+        Return the coroutine that needs to be synchronized during the test run.
+
+        This method is inteded to be overwritten by subclasses when they need to apply
+        the coroutine synchronizer to a value that's different from self.obj
+        e.g. the AsyncHypothesisTest subclass.
+        """
+        return self, "obj"
+
 
 class Coroutine(PytestAsyncioFunction):
     """Pytest item created by a coroutine"""
@@ -419,12 +508,6 @@ class Coroutine(PytestAsyncioFunction):
         func = item.obj
         return inspect.iscoroutinefunction(func)
 
-    def runtest(self) -> None:
-        synchronized_obj = wrap_in_sync(self.obj)
-        with MonkeyPatch.context() as c:
-            c.setattr(self, "obj", synchronized_obj)
-            super().runtest()
-
 
 class AsyncGenerator(PytestAsyncioFunction):
     """Pytest item created by an asynchronous generator"""
@@ -461,12 +544,6 @@ class AsyncStaticMethod(PytestAsyncioFun
             func.__func__
         )
 
-    def runtest(self) -> None:
-        synchronized_obj = wrap_in_sync(self.obj)
-        with MonkeyPatch.context() as c:
-            c.setattr(self, "obj", synchronized_obj)
-            super().runtest()
-
 
 class AsyncHypothesisTest(PytestAsyncioFunction):
     """
@@ -474,6 +551,16 @@ class AsyncHypothesisTest(PytestAsyncioF
     @hypothesis.given.
     """
 
+    def setup(self) -> None:
+        if not getattr(self.obj, "hypothesis", False) and getattr(
+            self.obj, "is_hypothesis_test", False
+        ):
+            pytest.fail(
+                f"test function `{self!r}` is using Hypothesis, but pytest-asyncio "
+                "only works with Hypothesis 3.64.0 or later."
+            )
+        return super().setup()
+
     @staticmethod
     def _can_substitute(item: Function) -> bool:
         func = item.obj
@@ -483,11 +570,9 @@ class AsyncHypothesisTest(PytestAsyncioF
             and inspect.iscoroutinefunction(func.hypothesis.inner_test)
         )
 
-    def runtest(self) -> 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()
+    @property
+    def _synchronization_target_attr(self) -> tuple[object, str]:
+        return self.obj.hypothesis, "inner_test"
 
 
 # The function name needs to start with "pytest_"
@@ -577,14 +662,9 @@ def _set_event_loop(loop: AbstractEventL
 
 @pytest.hookimpl(tryfirst=True, hookwrapper=True)
 def pytest_pyfunc_call(pyfuncitem: Function) -> object | None:
-    """
-    Pytest hook called before a test case is run.
-
-    Wraps marked tests in a synchronous function
-    where the wrapped test coroutine is executed in an event loop.
-    """
+    """Pytest hook called before a test case is run."""
     if pyfuncitem.get_closest_marker("asyncio") is not None:
-        if isinstance(pyfuncitem, PytestAsyncioFunction):
+        if is_async_test(pyfuncitem):
             asyncio_mode = _get_asyncio_mode(pyfuncitem.config)
             for fixname, fixtures in pyfuncitem._fixtureinfo.name2fixturedefs.items():
                 # name2fixturedefs is a dict between fixture name and a list of matching
@@ -603,7 +683,7 @@ def pytest_pyfunc_call(pyfuncitem: Funct
                             "You might want to use @pytest_asyncio.fixture or switch "
                             "to auto mode. "
                             "This will become an error in future versions of "
-                            "flake8-asyncio."
+                            "pytest-asyncio."
                         ),
                         stacklevel=1,
                     )
@@ -625,52 +705,24 @@ def pytest_pyfunc_call(pyfuncitem: Funct
     return None
 
 
-def wrap_in_sync(
-    func: Callable[..., Awaitable[Any]],
+def _synchronize_coroutine(
+    func: Callable[..., CoroutineType],
+    runner: asyncio.Runner,
+    context: contextvars.Context,
 ):
     """
-    Return a sync wrapper around an async function executing it in the
-    current event loop.
+    Return a sync wrapper around a coroutine executing it in the
+    specified runner and context.
     """
 
     @functools.wraps(func)
     def inner(*args, **kwargs):
         coro = func(*args, **kwargs)
-        _loop = _get_event_loop_no_warn()
-        task = asyncio.ensure_future(coro, loop=_loop)
-        try:
-            _loop.run_until_complete(task)
-        except BaseException:
-            # run_until_complete doesn't get the result from exceptions
-            # that are not subclasses of `Exception`. Consume all
-            # exceptions to prevent asyncio's warning from logging.
-            if task.done() and not task.cancelled():
-                task.exception()
-            raise
+        runner.run(coro, context=context)
 
     return inner
 
 
-def pytest_runtest_setup(item: pytest.Item) -> None:
-    marker = item.get_closest_marker("asyncio")
-    if marker is None:
-        return
-    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 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
-    ):
-        pytest.fail(
-            f"test function `{item!r}` is using Hypothesis, but pytest-asyncio "
-            "only works with Hypothesis 3.64.0 or later."
-        )
-
-
 @pytest.hookimpl(wrapper=True)
 def pytest_fixture_setup(fixturedef: FixtureDef, request) -> object | None:
     asyncio_mode = _get_asyncio_mode(request.config)
@@ -729,7 +781,7 @@ def _get_marked_loop_scope(
     return scope
 
 
-def _get_default_test_loop_scope(config: Config) -> _ScopeName:
+def _get_default_test_loop_scope(config: Config) -> Any:
     return config.getini("asyncio_default_test_loop_scope")
 
 
@@ -751,10 +803,12 @@ def _create_scoped_runner_fixture(scope:
     )
     def _scoped_runner(
         event_loop_policy,
+        request: FixtureRequest,
     ) -> Iterator[Runner]:
         new_loop_policy = event_loop_policy
+        debug_mode = _get_asyncio_debug(request.config)
         with _temporary_event_loop_policy(new_loop_policy):
-            runner = Runner().__enter__()
+            runner = Runner(debug=debug_mode).__enter__()
             try:
                 yield runner
             except Exception as e:
@@ -787,7 +841,7 @@ def event_loop_policy() -> AbstractEvent
     return _get_event_loop_policy()
 
 
-def is_async_test(item: Item) -> bool:
+def is_async_test(item: Item) -> TypeIs[PytestAsyncioFunction]:
     """Returns whether a test item is a pytest-asyncio test"""
     return isinstance(item, PytestAsyncioFunction)
 
diff -pruN 1.1.0-2/setup.cfg 1.2.0-1/setup.cfg
--- 1.1.0-2/setup.cfg	2025-07-16 03:50:17.000000000 +0000
+++ 1.2.0-1/setup.cfg	1970-01-01 00:00:00.000000000 +0000
@@ -1,18 +0,0 @@
-[metadata]
-# Not everything is in in pyproject.toml because of this issue:
-; Traceback (most recent call last):
-;  File "/tmp/build-env-rud8b5r6/lib/python3.12/site-packages/setuptools/config/expand.py", line 69, in __getattr__
-;    return next(
-;           ^^^^^
-;StopIteration
-;
-;The above exception was the direct cause of the following exception:
-;
-;Traceback (most recent call last):
-;  File "/tmp/build-env-rud8b5r6/lib/python3.12/site-packages/setuptools/config/expand.py", line 183, in read_attr
-;    return getattr(StaticModule(module_name, spec), attr_name)
-;           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-;  File "/tmp/build-env-rud8b5r6/lib/python3.12/site-packages/setuptools/config/expand.py", line 75, in __getattr__
-;    raise AttributeError(f"{self.name} has no attribute {attr}") from e
-;AttributeError: pytest_asyncio has no attribute __version__
-version = attr: pytest_asyncio.__version__
diff -pruN 1.1.0-2/tests/async_fixtures/test_async_fixtures_contextvars.py 1.2.0-1/tests/async_fixtures/test_async_fixtures_contextvars.py
--- 1.1.0-2/tests/async_fixtures/test_async_fixtures_contextvars.py	2025-07-16 03:50:17.000000000 +0000
+++ 1.2.0-1/tests/async_fixtures/test_async_fixtures_contextvars.py	2025-09-12 07:21:22.000000000 +0000
@@ -6,7 +6,9 @@ contextvars were not properly maintained
 from __future__ import annotations
 
 from textwrap import dedent
+from typing import Literal
 
+import pytest
 from pytest import Pytester
 
 _prelude = dedent(
@@ -213,3 +215,56 @@ def test_var_set_to_existing_value_ok(py
     )
     result = pytester.runpytest("--asyncio-mode=strict")
     result.assert_outcomes(passed=1)
+
+
+def test_no_isolation_against_context_changes_in_sync_tests(pytester: Pytester):
+    pytester.makeini("[pytest]\nasyncio_default_fixture_loop_scope = function")
+    pytester.makepyfile(
+        dedent(
+            """
+            import pytest
+            import pytest_asyncio
+            from contextvars import ContextVar
+
+            _context_var = ContextVar("my_var")
+
+            def test_sync():
+                _context_var.set("new_value")
+
+            @pytest.mark.asyncio
+            async def test_async():
+                assert _context_var.get() == "new_value"
+            """
+        )
+    )
+    result = pytester.runpytest("--asyncio-mode=strict")
+    result.assert_outcomes(passed=2)
+
+
+@pytest.mark.parametrize("loop_scope", ("function", "module"))
+def test_isolation_against_context_changes_in_async_tests(
+    pytester: Pytester, loop_scope: Literal["function", "module"]
+):
+    pytester.makeini("[pytest]\nasyncio_default_fixture_loop_scope = function")
+    pytester.makepyfile(
+        dedent(
+            f"""
+            import pytest
+            import pytest_asyncio
+            from contextvars import ContextVar
+
+            _context_var = ContextVar("my_var")
+
+            @pytest.mark.asyncio(loop_scope="{loop_scope}")
+            async def test_async_first():
+                _context_var.set("new_value")
+
+            @pytest.mark.asyncio(loop_scope="{loop_scope}")
+            async def test_async_second():
+                with pytest.raises(LookupError):
+                    _context_var.get()
+            """
+        )
+    )
+    result = pytester.runpytest("--asyncio-mode=strict")
+    result.assert_outcomes(passed=2)
diff -pruN 1.1.0-2/tests/markers/test_function_scope.py 1.2.0-1/tests/markers/test_function_scope.py
--- 1.1.0-2/tests/markers/test_function_scope.py	2025-07-16 03:50:17.000000000 +0000
+++ 1.2.0-1/tests/markers/test_function_scope.py	2025-09-12 07:21:22.000000000 +0000
@@ -87,7 +87,7 @@ def test_warns_when_scope_argument_is_pr
             """
         )
     )
-    result = pytester.runpytest_subprocess("--asyncio-mode=strict")
+    result = pytester.runpytest("--asyncio-mode=strict", "--assert=plain")
     result.assert_outcomes(passed=1, warnings=1)
     result.stdout.fnmatch_lines("*DeprecationWarning*")
 
@@ -157,7 +157,7 @@ def test_asyncio_mark_respects_parametri
             """
         )
     )
-    result = pytester.runpytest_subprocess("--asyncio-mode=strict")
+    result = pytester.runpytest("--asyncio-mode=strict")
     result.assert_outcomes(passed=2)
 
 
@@ -188,7 +188,7 @@ def test_asyncio_mark_provides_function_
             """
         )
     )
-    result = pytester.runpytest_subprocess("--asyncio-mode=strict")
+    result = pytester.runpytest("--asyncio-mode=strict")
     result.assert_outcomes(passed=1)
 
 
@@ -242,7 +242,7 @@ def test_standalone_test_does_not_trigge
             """
         )
     )
-    result = pytester.runpytest_subprocess("--asyncio-mode=strict")
+    result = pytester.runpytest("--asyncio-mode=strict", "--assert=plain")
     result.assert_outcomes(warnings=0, passed=1)
 
 
@@ -274,5 +274,5 @@ def test_asyncio_mark_does_not_duplicate
             """
         )
     )
-    result = pytester.runpytest_subprocess("--asyncio-mode=auto")
+    result = pytester.runpytest("--asyncio-mode=auto", "--assert=plain")
     result.assert_outcomes(warnings=0, passed=1)
diff -pruN 1.1.0-2/tests/modes/test_strict_mode.py 1.2.0-1/tests/modes/test_strict_mode.py
--- 1.1.0-2/tests/modes/test_strict_mode.py	2025-07-16 03:50:17.000000000 +0000
+++ 1.2.0-1/tests/modes/test_strict_mode.py	2025-09-12 07:21:22.000000000 +0000
@@ -173,7 +173,7 @@ def test_strict_mode_marked_test_unmarke
                 "@pytest.fixture 'any_fixture' in strict mode. "
                 "You might want to use @pytest_asyncio.fixture or switch to "
                 "auto mode. "
-                "This will become an error in future versions of flake8-asyncio."
+                "This will become an error in future versions of pytest-asyncio."
             ),
         ],
     )
@@ -220,7 +220,7 @@ def test_strict_mode_marked_test_unmarke
                 "@pytest.fixture 'any_fixture' in strict mode. "
                 "You might want to use @pytest_asyncio.fixture or switch to "
                 "auto mode. "
-                "This will become an error in future versions of flake8-asyncio."
+                "This will become an error in future versions of pytest-asyncio."
             ),
         ],
     )
diff -pruN 1.1.0-2/tests/test_asyncio_debug.py 1.2.0-1/tests/test_asyncio_debug.py
--- 1.1.0-2/tests/test_asyncio_debug.py	1970-01-01 00:00:00.000000000 +0000
+++ 1.2.0-1/tests/test_asyncio_debug.py	2025-09-12 07:21:22.000000000 +0000
@@ -0,0 +1,216 @@
+from __future__ import annotations
+
+from textwrap import dedent
+
+import pytest
+from pytest import Pytester
+
+
+def test_asyncio_debug_disabled_by_default(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_debug_mode_disabled():
+                loop = asyncio.get_running_loop()
+                assert not loop.get_debug()
+            """
+        )
+    )
+    result = pytester.runpytest()
+    result.assert_outcomes(passed=1)
+
+
+def test_asyncio_debug_enabled_via_cli_option(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_debug_mode_enabled():
+                loop = asyncio.get_running_loop()
+                assert loop.get_debug()
+            """
+        )
+    )
+    result = pytester.runpytest("--asyncio-debug")
+    result.assert_outcomes(passed=1)
+
+
+@pytest.mark.parametrize("config_value", ("true", "1"))
+def test_asyncio_debug_enabled_via_config_option(pytester: Pytester, config_value: str):
+    pytester.makeini(
+        dedent(
+            f"""\
+            [pytest]
+            asyncio_default_fixture_loop_scope = function
+            asyncio_debug = {config_value}
+            """
+        )
+    )
+    pytester.makepyfile(
+        dedent(
+            """\
+            import asyncio
+            import pytest
+
+            pytest_plugins = "pytest_asyncio"
+
+            @pytest.mark.asyncio
+            async def test_debug_mode_enabled():
+                loop = asyncio.get_running_loop()
+                assert loop.get_debug()
+            """
+        )
+    )
+    result = pytester.runpytest()
+    result.assert_outcomes(passed=1)
+
+
+@pytest.mark.parametrize("config_value", ("false", "0"))
+def test_asyncio_debug_disabled_via_config_option(
+    pytester: Pytester,
+    config_value: str,
+):
+    pytester.makeini(
+        dedent(
+            f"""\
+            [pytest]
+            asyncio_default_fixture_loop_scope = function
+            asyncio_debug = {config_value}
+            """
+        )
+    )
+    pytester.makepyfile(
+        dedent(
+            """\
+            import asyncio
+            import pytest
+
+            pytest_plugins = "pytest_asyncio"
+
+            @pytest.mark.asyncio
+            async def test_debug_mode_disabled():
+                loop = asyncio.get_running_loop()
+                assert not loop.get_debug()
+            """
+        )
+    )
+    result = pytester.runpytest()
+    result.assert_outcomes(passed=1)
+
+
+def test_asyncio_debug_cli_option_overrides_config(pytester: Pytester):
+    pytester.makeini(
+        "[pytest]\nasyncio_default_fixture_loop_scope = function\nasyncio_debug = false"
+    )
+    pytester.makepyfile(
+        dedent(
+            """\
+            import asyncio
+            import pytest
+
+            pytest_plugins = "pytest_asyncio"
+
+            @pytest.mark.asyncio
+            async def test_debug_mode_enabled():
+                loop = asyncio.get_running_loop()
+                assert loop.get_debug()
+            """
+        )
+    )
+    result = pytester.runpytest("--asyncio-debug")
+    result.assert_outcomes(passed=1)
+
+
+@pytest.mark.parametrize("loop_scope", ("function", "module", "session"))
+def test_asyncio_debug_with_different_loop_scopes(pytester: Pytester, loop_scope: str):
+    pytester.makeini("[pytest]\nasyncio_default_fixture_loop_scope = function")
+    pytester.makepyfile(
+        dedent(
+            f"""\
+            import asyncio
+            import pytest
+
+            pytest_plugins = "pytest_asyncio"
+
+            @pytest.mark.asyncio(loop_scope="{loop_scope}")
+            async def test_debug_mode_with_scope():
+                loop = asyncio.get_running_loop()
+                assert loop.get_debug()
+            """
+        )
+    )
+    result = pytester.runpytest("--asyncio-debug")
+    result.assert_outcomes(passed=1)
+
+
+def test_asyncio_debug_with_async_fixtures(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 async_fixture():
+                loop = asyncio.get_running_loop()
+                assert loop.get_debug()
+                return "fixture_value"
+
+            @pytest.mark.asyncio
+            async def test_debug_mode_with_fixture(async_fixture):
+                loop = asyncio.get_running_loop()
+                assert loop.get_debug()
+                assert async_fixture == "fixture_value"
+            """
+        )
+    )
+    result = pytester.runpytest("--asyncio-debug")
+    result.assert_outcomes(passed=1)
+
+
+def test_asyncio_debug_multiple_test_functions(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_debug_first():
+                loop = asyncio.get_running_loop()
+                assert loop.get_debug()
+
+            @pytest.mark.asyncio
+            async def test_debug_second():
+                loop = asyncio.get_running_loop()
+                assert loop.get_debug()
+
+            @pytest.mark.asyncio
+            async def test_debug_third():
+                loop = asyncio.get_running_loop()
+                assert loop.get_debug()
+            """
+        )
+    )
+    result = pytester.runpytest("--asyncio-debug")
+    result.assert_outcomes(passed=3)
diff -pruN 1.1.0-2/tests/test_fixture_loop_scopes.py 1.2.0-1/tests/test_fixture_loop_scopes.py
--- 1.1.0-2/tests/test_fixture_loop_scopes.py	2025-07-16 03:50:17.000000000 +0000
+++ 1.2.0-1/tests/test_fixture_loop_scopes.py	2025-09-12 07:21:22.000000000 +0000
@@ -136,3 +136,20 @@ def test_default_package_loop_scope_conf
     )
     result = pytester.runpytest_subprocess("--asyncio-mode=strict")
     result.assert_outcomes(passed=1)
+
+
+def test_invalid_default_fixture_loop_scope_raises_error(pytester: Pytester):
+    pytester.makeini(
+        """\
+        [pytest]
+        asyncio_default_fixture_loop_scope = invalid_scope
+        """
+    )
+    result = pytester.runpytest()
+    result.stderr.fnmatch_lines(
+        [
+            "ERROR: 'invalid_scope' is not a valid "
+            "asyncio_default_fixture_loop_scope. Valid scopes are: "
+            "function, class, module, package, session."
+        ]
+    )
diff -pruN 1.1.0-2/tests/test_package.py 1.2.0-1/tests/test_package.py
--- 1.1.0-2/tests/test_package.py	1970-01-01 00:00:00.000000000 +0000
+++ 1.2.0-1/tests/test_package.py	2025-09-12 07:21:22.000000000 +0000
@@ -0,0 +1,5 @@
+import pytest_asyncio
+
+
+def test_package_exposes_version():
+    assert pytest_asyncio.__version__
diff -pruN 1.1.0-2/tests/test_set_event_loop.py 1.2.0-1/tests/test_set_event_loop.py
--- 1.1.0-2/tests/test_set_event_loop.py	1970-01-01 00:00:00.000000000 +0000
+++ 1.2.0-1/tests/test_set_event_loop.py	2025-09-12 07:21:22.000000000 +0000
@@ -0,0 +1,371 @@
+from __future__ import annotations
+
+import sys
+from textwrap import dedent
+
+import pytest
+from pytest import Pytester
+
+
+@pytest.mark.parametrize(
+    "test_loop_scope",
+    ("function", "module", "package", "session"),
+)
+@pytest.mark.parametrize(
+    "loop_breaking_action",
+    [
+        "asyncio.set_event_loop(None)",
+        "asyncio.run(asyncio.sleep(0))",
+        pytest.param(
+            "with asyncio.Runner(): pass",
+            marks=pytest.mark.skipif(
+                sys.version_info < (3, 11),
+                reason="asyncio.Runner requires Python 3.11+",
+            ),
+        ),
+    ],
+)
+def test_set_event_loop_none(
+    pytester: Pytester,
+    test_loop_scope: str,
+    loop_breaking_action: str,
+):
+    pytester.makeini(
+        dedent(
+            f"""\
+            [pytest]
+            asyncio_default_test_loop_scope = {test_loop_scope}
+            asyncio_default_fixture_loop_scope = function
+            """
+        )
+    )
+    pytester.makepyfile(
+        dedent(
+            f"""\
+            import asyncio
+            import pytest
+
+            pytest_plugins = "pytest_asyncio"
+
+            @pytest.mark.asyncio
+            async def test_before():
+                pass
+
+            def test_set_event_loop_none():
+                {loop_breaking_action}
+
+            @pytest.mark.asyncio
+            async def test_after():
+                pass
+            """
+        )
+    )
+    result = pytester.runpytest_subprocess()
+    result.assert_outcomes(passed=3)
+
+
+@pytest.mark.parametrize(
+    "loop_breaking_action",
+    [
+        "asyncio.set_event_loop(None)",
+        "asyncio.run(asyncio.sleep(0))",
+        pytest.param(
+            "with asyncio.Runner(): pass",
+            marks=pytest.mark.skipif(
+                sys.version_info < (3, 11),
+                reason="asyncio.Runner requires Python 3.11+",
+            ),
+        ),
+    ],
+)
+def test_set_event_loop_none_class(pytester: Pytester, loop_breaking_action: str):
+    pytester.makeini(
+        dedent(
+            """\
+            [pytest]
+            asyncio_default_test_loop_scope = class
+            asyncio_default_fixture_loop_scope = function
+            """
+        )
+    )
+    pytester.makepyfile(
+        dedent(
+            f"""\
+            import asyncio
+            import pytest
+
+            pytest_plugins = "pytest_asyncio"
+
+
+            class TestClass:
+                @pytest.mark.asyncio
+                async def test_before(self):
+                    pass
+
+                def test_set_event_loop_none(self):
+                    {loop_breaking_action}
+
+                @pytest.mark.asyncio
+                async def test_after(self):
+                    pass
+            """
+        )
+    )
+    result = pytester.runpytest_subprocess()
+    result.assert_outcomes(passed=3)
+
+
+@pytest.mark.parametrize("test_loop_scope", ("module", "package", "session"))
+@pytest.mark.parametrize(
+    "loop_breaking_action",
+    [
+        "asyncio.set_event_loop(None)",
+        "asyncio.run(asyncio.sleep(0))",
+        pytest.param(
+            "with asyncio.Runner(): pass",
+            marks=pytest.mark.skipif(
+                sys.version_info < (3, 11),
+                reason="asyncio.Runner requires Python 3.11+",
+            ),
+        ),
+    ],
+)
+def test_original_shared_loop_is_reinstated_not_fresh_loop(
+    pytester: Pytester,
+    test_loop_scope: str,
+    loop_breaking_action: str,
+):
+    pytester.makeini(
+        dedent(
+            f"""\
+            [pytest]
+            asyncio_default_test_loop_scope = {test_loop_scope}
+            asyncio_default_fixture_loop_scope = function
+            """
+        )
+    )
+    pytester.makepyfile(
+        dedent(
+            f"""\
+            import asyncio
+            import pytest
+
+            pytest_plugins = "pytest_asyncio"
+
+            original_shared_loop: asyncio.AbstractEventLoop = None
+
+            @pytest.mark.asyncio
+            async def test_store_original_shared_loop():
+                global original_shared_loop
+                original_shared_loop = asyncio.get_running_loop()
+                original_shared_loop._custom_marker = "original_loop_marker"
+
+            def test_unset_event_loop():
+                {loop_breaking_action}
+
+            @pytest.mark.asyncio
+            async def test_verify_original_loop_reinstated():
+                global original_shared_loop
+                current_loop = asyncio.get_running_loop()
+                assert current_loop is original_shared_loop
+                assert hasattr(current_loop, '_custom_marker')
+                assert current_loop._custom_marker == "original_loop_marker"
+            """
+        )
+    )
+    result = pytester.runpytest_subprocess("--asyncio-mode=strict")
+    result.assert_outcomes(passed=3)
+
+
+@pytest.mark.parametrize("test_loop_scope", ("module", "package", "session"))
+@pytest.mark.parametrize(
+    "loop_breaking_action",
+    [
+        "asyncio.set_event_loop(None)",
+        "asyncio.run(asyncio.sleep(0))",
+        pytest.param(
+            "with asyncio.Runner(): pass",
+            marks=pytest.mark.skipif(
+                sys.version_info < (3, 11),
+                reason="asyncio.Runner requires Python 3.11+",
+            ),
+        ),
+    ],
+)
+def test_shared_loop_with_fixture_preservation(
+    pytester: Pytester,
+    test_loop_scope: str,
+    loop_breaking_action: str,
+):
+    pytester.makeini(
+        dedent(
+            f"""\
+            [pytest]
+            asyncio_default_test_loop_scope = {test_loop_scope}
+            asyncio_default_fixture_loop_scope = {test_loop_scope}
+            """
+        )
+    )
+    pytester.makepyfile(
+        dedent(
+            f"""\
+            import asyncio
+            import pytest
+            import pytest_asyncio
+
+            pytest_plugins = "pytest_asyncio"
+
+            fixture_loop: asyncio.AbstractEventLoop = None
+            long_running_task = None
+
+            @pytest_asyncio.fixture
+            async def webserver():
+                global fixture_loop, long_running_task
+                fixture_loop = asyncio.get_running_loop()
+
+                async def background_task():
+                    while True:
+                        await asyncio.sleep(1)
+
+                long_running_task = asyncio.create_task(background_task())
+                yield
+                long_running_task.cancel()
+
+
+            @pytest.mark.asyncio
+            async def test_before(webserver):
+                global fixture_loop, long_running_task
+                assert asyncio.get_running_loop() is fixture_loop
+                assert not long_running_task.done()
+
+
+            def test_set_event_loop_none():
+                {loop_breaking_action}
+
+
+            @pytest.mark.asyncio
+            async def test_after(webserver):
+                global fixture_loop, long_running_task
+                current_loop = asyncio.get_running_loop()
+                assert current_loop is fixture_loop
+                assert not long_running_task.done()
+            """
+        )
+    )
+    result = pytester.runpytest_subprocess("--asyncio-mode=strict")
+    result.assert_outcomes(passed=3)
+
+
+@pytest.mark.parametrize(
+    "first_scope,second_scope",
+    [
+        ("module", "session"),
+        ("session", "module"),
+        ("package", "session"),
+        ("session", "package"),
+        ("package", "module"),
+        ("module", "package"),
+    ],
+)
+@pytest.mark.parametrize(
+    "loop_breaking_action",
+    [
+        "asyncio.set_event_loop(None)",
+        "asyncio.run(asyncio.sleep(0))",
+        pytest.param(
+            "with asyncio.Runner(): pass",
+            marks=pytest.mark.skipif(
+                sys.version_info < (3, 11),
+                reason="asyncio.Runner requires Python 3.11+",
+            ),
+        ),
+    ],
+)
+def test_shared_loop_with_multiple_fixtures_preservation(
+    pytester: Pytester,
+    first_scope: str,
+    second_scope: str,
+    loop_breaking_action: str,
+):
+    pytester.makeini(
+        dedent(
+            """\
+            [pytest]
+            asyncio_default_test_loop_scope = session
+            asyncio_default_fixture_loop_scope = session
+            """
+        )
+    )
+    pytester.makepyfile(
+        dedent(
+            f"""\
+            import asyncio
+            import pytest
+            import pytest_asyncio
+
+            pytest_plugins = "pytest_asyncio"
+
+            first_fixture_loop: asyncio.AbstractEventLoop = None
+            second_fixture_loop: asyncio.AbstractEventLoop = None
+            first_long_running_task = None
+            second_long_running_task = None
+
+            @pytest_asyncio.fixture(scope="{first_scope}", loop_scope="{first_scope}")
+            async def first_webserver():
+                global first_fixture_loop, first_long_running_task
+                first_fixture_loop = asyncio.get_running_loop()
+
+                async def background_task():
+                    while True:
+                        await asyncio.sleep(0.1)
+
+                first_long_running_task = asyncio.create_task(background_task())
+                yield
+                first_long_running_task.cancel()
+
+            @pytest_asyncio.fixture(scope="{second_scope}", loop_scope="{second_scope}")
+            async def second_webserver():
+                global second_fixture_loop, second_long_running_task
+                second_fixture_loop = asyncio.get_running_loop()
+
+                async def background_task():
+                    while True:
+                        await asyncio.sleep(0.1)
+
+                second_long_running_task = asyncio.create_task(background_task())
+                yield
+                second_long_running_task.cancel()
+
+            @pytest.mark.asyncio(loop_scope="{first_scope}")
+            async def test_before_first(first_webserver):
+                global first_fixture_loop, first_long_running_task
+                assert asyncio.get_running_loop() is first_fixture_loop
+                assert not first_long_running_task.done()
+
+            @pytest.mark.asyncio(loop_scope="{second_scope}")
+            async def test_before_second(second_webserver):
+                global second_fixture_loop, second_long_running_task
+                assert asyncio.get_running_loop() is second_fixture_loop
+                assert not second_long_running_task.done()
+
+            def test_set_event_loop_none():
+                {loop_breaking_action}
+
+            @pytest.mark.asyncio(loop_scope="{first_scope}")
+            async def test_after_first(first_webserver):
+                global first_fixture_loop, first_long_running_task
+                current_loop = asyncio.get_running_loop()
+                assert current_loop is first_fixture_loop
+                assert not first_long_running_task.done()
+
+            @pytest.mark.asyncio(loop_scope="{second_scope}")
+            async def test_after_second(second_webserver):
+                global second_fixture_loop, second_long_running_task
+                current_loop = asyncio.get_running_loop()
+                assert current_loop is second_fixture_loop
+                assert not second_long_running_task.done()
+            """
+        )
+    )
+    result = pytester.runpytest_subprocess("--asyncio-mode=strict")
+    result.assert_outcomes(passed=5)
diff -pruN 1.1.0-2/tox.ini 1.2.0-1/tox.ini
--- 1.1.0-2/tox.ini	2025-07-16 03:50:17.000000000 +0000
+++ 1.2.0-1/tox.ini	2025-09-12 07:21:22.000000000 +0000
@@ -1,26 +1,41 @@
 [tox]
-minversion = 4.9.0
-envlist = py39, py310, py311, py312, py313, py314, pytest-min, docs
+minversion = 4.28.0
+envlist = build, py39, py310, py311, py312, py313, py314, pytest-min, docs, pyright
 isolated_build = true
 passenv =
     CI
 
+[pkgenv]
+constraints = constraints.txt
+
 [testenv]
+package = external
 extras = testing
-install_command = python -m pip install \
-    --requirement dependencies/default/requirements.txt \
-    --constraint dependencies/default/constraints.txt \
-    {opts} {packages}
+constraints = constraints.txt
 commands = make test
 allowlist_externals =
     make
 
+[testenv:.pkg_external]
+deps = build
+package_glob = {toxinidir}{/}dist{/}*.whl
+commands =
+    python -c 'import shutil; shutil.rmtree("{toxinidir}{/}dist", ignore_errors=True)'
+    pyproject-build --outdir {toxinidir}{/}dist .
+
+[testenv:build]
+description = Check distribution files
+deps =
+    check-wheel-contents
+    twine
+commands =
+    check-wheel-contents {toxinidir}{/}dist
+    twine check {toxinidir}{/}dist{/}*
+
 [testenv:pytest-min]
 extras = testing
-install_command = python -m pip install \
-    --requirement dependencies/pytest-min/requirements.txt \
-    --constraint dependencies/pytest-min/constraints.txt \
-    {opts} {packages}
+constraints = dependencies/pytest-min/constraints.txt
+deps = -r dependencies/pytest-min/requirements.txt
 commands = make test
 allowlist_externals =
     make
@@ -29,9 +44,6 @@ allowlist_externals =
 allowlist_externals =
     git
 extras = docs
-deps =
-     --requirement dependencies/docs/requirements.txt
-     --constraint dependencies/docs/constraints.txt
 change_dir = docs
 description = Build The Docs with {basepython}
 commands =
@@ -69,12 +81,19 @@ passenv =
     SSH_AUTH_SOCK
 skip_install = false
 
+[testenv:pyright]
+deps =
+    pyright[nodejs]
+    pytest
+commands = pyright pytest_asyncio/
+skip_install = true
+
 [gh-actions]
 python =
-    3.9: py39, pytest-min
+    3.9: py39, pytest-min, build
     3.10: py310
     3.11: py311
     3.12: py312
-    3.13: py313
+    3.13: py313, pyright
     3.14-dev: py314
     pypy3: pypy3
