Skip to content

Conversation

@kovan
Copy link
Contributor

@kovan kovan commented Feb 8, 2026

Summary

Adds a focused HOWTO for building a TCP chat server with asyncio streams, as suggested by @ZeroIntensity in the review of #144594:

There are some things here that look useful for the docs, but I don't think they need to be put under an "asyncio tutorial" umbrella. Instead, let's just make a HOWTO page for a chat server, since that seems to be the primary focus of all the content here.

The guide progressively builds from an echo server to a full chat server:

  • Starting with an echo server — introduces the streams API (start_server, StreamReader/StreamWriter, write/drain, close/wait_closed)
  • Building the chat server — adds client tracking, broadcasting, and cleanup
  • Extending the chat server — idle timeouts with asyncio.timeout, plus exercises
  • Common pitfalls — forgetting to await, blocking the event loop, fire-and-forget tasks

No overlap with the existing Conceptual Overview — this is purely a practical, hands-on HOWTO.

Test plan

  • make -C Doc check passes
  • make -C Doc html passes (no warnings)
  • All cross-references resolve correctly

🤖 Generated with Claude Code


📚 Documentation preview 📚: https://cpython-previews--144604.org.readthedocs.build/

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@bedevere-app bedevere-app bot mentioned this pull request Feb 8, 2026
@bedevere-app bedevere-app bot added docs Documentation in the Doc dir skip news labels Feb 8, 2026
@github-project-automation github-project-automation bot moved this to Todo in Docs PRs Feb 8, 2026
@ZeroIntensity ZeroIntensity self-requested a review February 9, 2026 11:59
Comment on lines 266 to 267
Common pitfalls
===============
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This section isn't really about the chat server. These are just common asyncio traps that would fit better in the tutorial or the reference docs.

- Explain concepts (start_server, StreamReader/StreamWriter) before code
- Use asyncio.TaskGroup for concurrent broadcasting
- Use contextlib.suppress instead of bare except/pass
- Remove Python test client, keep only nc/telnet
- Properly explain asyncio.timeout before showing usage
- Move implementation notes to code comments
- Remove Exercises and Common pitfalls sections
- Reorder seealso links in asyncio.rst

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@kovan
Copy link
Contributor Author

kovan commented Feb 10, 2026

I have made the requested changes; please review again

@bedevere-app
Copy link

bedevere-app bot commented Feb 10, 2026

Thanks for making the requested changes!

: please review the changes made to this pull request.

Comment on lines 68 to 73
The :meth:`~asyncio.StreamWriter.write` method buffers data without sending
it immediately. Awaiting :meth:`~asyncio.StreamWriter.drain` flushes the
buffer and applies back-pressure if the client is slow to read. Similarly,
:meth:`~asyncio.StreamWriter.close` initiates shutdown, and awaiting
:meth:`~asyncio.StreamWriter.wait_closed` waits until the connection is
fully closed.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should go above the example.

Comment on lines 97 to 110
::

import asyncio
import contextlib

connected_clients: dict[str, asyncio.StreamWriter] = {}

async def broadcast(message, *, sender=None):
"""Send a message to all connected clients except the sender."""
async def send(writer):
with contextlib.suppress(ConnectionError):
writer.write(message.encode())
await writer.drain()

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code is really large. We should introduce small concepts and explain things, and then finally show the complete example at the end.

Comment on lines +63 to +64
async with server:
await server.serve_forever()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't explained.

Comment on lines +54 to +55
writer.close()
await writer.wait_closed()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to be explained too.

- Move write/drain and close/wait_closed explanations above the echo
  server example
- Explain async with server, serve_forever, and asyncio.run
- Break chat server into subsections: client tracking, broadcasting,
  then the complete example
- Show broadcast function separately before the full listing

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@kovan
Copy link
Contributor Author

kovan commented Feb 10, 2026

I have made the requested changes; please review again

@bedevere-app
Copy link

bedevere-app bot commented Feb 10, 2026

Thanks for making the requested changes!

: please review the changes made to this pull request.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

2 participants