Repository: agronholm/anyio

Issue:
Backend specific options don't appear to be used
### Things to check first

- [X] I have searched the existing issues and didn't find my bug already reported there

- [X] I have checked that my bug is still present in the latest release


### AnyIO version

4.1.0

### Python version

3.11

### What happened?

As best as I can tell, the backend specific options for both the asyncio and trio options aren't being used

https://github.com/agronholm/anyio/blob/cc18942a384dcb881e78a81c898d7e89d4e1ce0b/src/anyio/_backends/_asyncio.py#L1939-L1960

https://github.com/agronholm/anyio/blob/cc18942a384dcb881e78a81c898d7e89d4e1ce0b/src/anyio/_backends/_trio.py#L807-L814

### How can we reproduce the bug?

I'm sorry if I'm missing something, but the backend options don't appear to be used, except for `debug` for asyncio. I don't have a test case, however, so, I apologize again if I'm not seeing how the options are getting applied.

Discussion:

Patch:
diff --git a/docs/versionhistory.rst b/docs/versionhistory.rst
index af625fd..78ef510 100644
--- a/docs/versionhistory.rst
+++ b/docs/versionhistory.rst
@@ -11,6 +11,8 @@ This library adheres to `Semantic Versioning 2.0 <http://semver.org/>`_.
 - Fixed adjusting the total number of tokens in a ``CapacityLimiter`` on asyncio failing
   to wake up tasks waiting to acquire the limiter in certain edge cases (fixed with help
   from Egor Blagov)
+- Fixed ``loop_factory`` and ``use_uvloop`` options not being used on the asyncio
+  backend (`#643 <https://github.com/agronholm/anyio/issues/643>`_)
 
 **4.1.0**
 
diff --git a/src/anyio/_backends/_asyncio.py b/src/anyio/_backends/_asyncio.py
index 7a10e17..bb6a9bf 100644
--- a/src/anyio/_backends/_asyncio.py
+++ b/src/anyio/_backends/_asyncio.py
@@ -16,7 +16,6 @@ from asyncio import (
     get_running_loop,
     sleep,
 )
-from asyncio import run as native_run
 from asyncio.base_events import _run_until_complete_cb  # type: ignore[attr-defined]
 from collections import OrderedDict, deque
 from collections.abc import AsyncIterator, Generator, Iterable
@@ -165,7 +164,7 @@ else:
 
             if context is None:
                 context = self._context
-            task = self._loop.create_task(coro, context=context)
+            task = context.run(self._loop.create_task, coro)
 
             if (
                 threading.current_thread() is threading.main_thread()
@@ -1950,9 +1949,14 @@ class AsyncIOBackend(AsyncBackend):
                 del _task_states[task]
 
         debug = options.get("debug", False)
-        options.get("loop_factory", None)
-        options.get("use_uvloop", False)
-        return native_run(wrapper(), debug=debug)
+        loop_factory = options.get("loop_factory", None)
+        if loop_factory is None and options.get("use_uvloop", False):
+            import uvloop
+
+            loop_factory = uvloop.new_event_loop
+
+        with Runner(debug=debug, loop_factory=loop_factory) as runner:
+            return runner.run(wrapper())
 
     @classmethod
     def current_token(cls) -> object:


Test patch:
diff --git a/tests/test_eventloop.py b/tests/test_eventloop.py
index c0c8ab5..73ad0c2 100644
--- a/tests/test_eventloop.py
+++ b/tests/test_eventloop.py
@@ -2,6 +2,7 @@ from __future__ import annotations
 
 import asyncio
 import math
+from asyncio import get_running_loop
 from unittest.mock import AsyncMock
 
 import pytest
@@ -44,3 +45,32 @@ def test_run_task() -> None:
 
     result = run(asyncio.create_task, async_add(1, 2), backend="asyncio")
     assert result == 3
+
+
+class TestAsyncioOptions:
+    def test_debug(self) -> None:
+        async def main() -> bool:
+            return get_running_loop().get_debug()
+
+        debug = run(main, backend="asyncio", backend_options={"debug": True})
+        assert debug is True
+
+    def test_loop_factory(self) -> None:
+        async def main() -> type:
+            return type(get_running_loop())
+
+        uvloop = pytest.importorskip("uvloop", reason="uvloop not installed")
+        loop_class = run(
+            main,
+            backend="asyncio",
+            backend_options={"loop_factory": uvloop.new_event_loop},
+        )
+        assert issubclass(loop_class, uvloop.Loop)
+
+    def test_use_uvloop(self) -> None:
+        async def main() -> type:
+            return type(get_running_loop())
+
+        uvloop = pytest.importorskip("uvloop", reason="uvloop not installed")
+        loop_class = run(main, backend="asyncio", backend_options={"use_uvloop": True})
+        assert issubclass(loop_class, uvloop.Loop)