Repository: agronholm/anyio

Issue:
TypeError: 'SocketListener' object is not iterable exception on MultiListener.extra() call
Call to ``MultiListener.extra()`` results in ``TypeError: 'SocketListener' object is not iterable``:

```
>>> import anyio
>>> listener = await anyio.create_tcp_listener(local_port=33333)
>>> listener.extra(anyio.abc.SocketAttribute.local_address)
Traceback (most recent call last):
  File ".../lib/python3.8/concurrent/futures/_base.py", line 439, in result
    return self.__get_result()
  File ".../lib/python3.8/concurrent/futures/_base.py", line 388, in __get_result
    raise self._exception
  File ".../lib/python3.8/asyncio/__main__.py", line 34, in callback
    coro = func()
  File "<console>", line 1, in <module>
  File ".../python3.8/site-packages/anyio/_core/_typedattr.py", line 74, in extra
    return self.extra_attributes[attribute]()
  File ".../lib/python3.8/site-packages/anyio/streams/stapled.py", line 123, in extra_attributes
    attributes.update(listener)
TypeError: 'SocketListener' object is not iterable
```

Discussion:
agronholm: Ouch, the one part of the code I didn't test...is of course broken :( But thanks for noticing and fixing it.
No clue what's up with curio not installing on macos+py3.8 but it doesn't look like a real error.

Patch:
diff --git a/src/anyio/streams/stapled.py b/src/anyio/streams/stapled.py
index c344d49..a0927c2 100644
--- a/src/anyio/streams/stapled.py
+++ b/src/anyio/streams/stapled.py
@@ -120,6 +120,6 @@ class MultiListener(Generic[T_Stream], Listener[T_Stream]):
     def extra_attributes(self):
         attributes = {}
         for listener in self.listeners:
-            attributes.update(listener)
+            attributes.update(listener.extra_attributes)
 
         return attributes


Test patch:
diff --git a/tests/test_sockets.py b/tests/test_sockets.py
index 8619aa6..24e59b7 100644
--- a/tests/test_sockets.py
+++ b/tests/test_sockets.py
@@ -316,6 +316,7 @@ class TestTCPStream:
 class TestTCPListener:
     async def test_extra_attributes(self, family):
         async with await create_tcp_listener(local_host='localhost', family=family) as multi:
+            assert multi.extra(SocketAttribute.family) == family
             for listener in multi.listeners:
                 raw_socket = listener.extra(SocketAttribute.raw_socket)
                 assert listener.extra(SocketAttribute.family) == family