Repository: agronholm/anyio

Issue:
On `trio` backend, `CapacityLimiter` does not take keyword arguments
MWE:
```
import anyio

async def test():
    lim = anyio.CapacityLimiter(total_tokens=1)
    async with lim:
        await anyio.sleep(0.5)
        
with anyio.start_blocking_portal(backend="trio") as portal:
    portal.start_task_soon(test).result()
```
fails with `TypeError: CapacityLimiter.__init__() got an unexpected keyword argument 'total_tokens'`.

This doesn't happen when supplying the tokens as positional arguments or when using the `asyncio` backend.




Discussion:

Patch:
diff --git a/docs/versionhistory.rst b/docs/versionhistory.rst
index 5f6500b..5d39e45 100644
--- a/docs/versionhistory.rst
+++ b/docs/versionhistory.rst
@@ -7,6 +7,9 @@ This library adheres to `Semantic Versioning 2.0 <http://semver.org/>`_.
 
 - Added support for the Python 3.12 ``walk_up`` keyword argument in
   ``anyio.Path.relative_to()`` (PR by Colin Taylor)
+- Fixed passing ``total_tokens`` to ``anyio.CapacityLimiter()`` as a keyword argument
+  not working on the ``trio`` backend
+  (`#515 <https://github.com/agronholm/anyio/issues/515>`_)
 
 **4.2.0**
 
diff --git a/src/anyio/_backends/_trio.py b/src/anyio/_backends/_trio.py
index a0d14c7..13b960f 100644
--- a/src/anyio/_backends/_trio.py
+++ b/src/anyio/_backends/_trio.py
@@ -631,14 +631,24 @@ class Event(BaseEvent):
 
 class CapacityLimiter(BaseCapacityLimiter):
     def __new__(
-        cls, *args: Any, original: trio.CapacityLimiter | None = None
+        cls,
+        total_tokens: float | None = None,
+        *,
+        original: trio.CapacityLimiter | None = None,
     ) -> CapacityLimiter:
         return object.__new__(cls)
 
     def __init__(
-        self, *args: Any, original: trio.CapacityLimiter | None = None
+        self,
+        total_tokens: float | None = None,
+        *,
+        original: trio.CapacityLimiter | None = None,
     ) -> None:
-        self.__original = original or trio.CapacityLimiter(*args)
+        if original is not None:
+            self.__original = original
+        else:
+            assert total_tokens is not None
+            self.__original = trio.CapacityLimiter(total_tokens)
 
     async def __aenter__(self) -> None:
         return await self.__original.__aenter__()


Test patch:
diff --git a/tests/test_synchronization.py b/tests/test_synchronization.py
index 5eddc06..d6f68f6 100644
--- a/tests/test_synchronization.py
+++ b/tests/test_synchronization.py
@@ -689,3 +689,8 @@ class TestCapacityLimiter:
             backend=anyio_backend_name,
             backend_options=anyio_backend_options,
         )
+
+    async def test_total_tokens_as_kwarg(self) -> None:
+        # Regression test for #515
+        limiter = CapacityLimiter(total_tokens=1)
+        assert limiter.total_tokens == 1