tornado — Cursor rule: async/await in Tornado apps
A Cursor rule that pins down Tornado code style: async/await for every I/O call, full type hints, and one shared error handler.
.cursor/rules/tornado.mdcWhat tornado does
The .cursor/rules/tornado.mdc file plugs into Cursor and applies to **/*.py. Inside is a set of Tornado conventions for Python 3.9+ with bad/good code samples. The agent reads them while editing and keeps new code in that shape.
The core demand is no blocking I/O in handlers. time.sleep stalls the IOLoop, so the rule swaps it for await asyncio.sleep. Same story with the older callback APIs: Tornado runs on top of asyncio, so any network or disk call should be async def with await. Second point is typing — from __future__ import annotations plus annotations on request arguments.
Errors get handled in one place. Tornado already deals with malformed headers and broken multipart-form-data, and the rule forbids catching those exceptions inside every handler. Instead it suggests a base class that returns a consistent response for HTTPError. If your project already has its own error layer, expect to rewrite the rule to match, otherwise the agent will keep pulling code toward the suggested scheme.
What it helps with
- strip blocking calls out of Tornado handlers
- move legacy code from callback APIs to async/await
- add type hints to handlers and request arguments
- route error responses through one base class
- stop catching malformed header and multipart exceptions by hand
Example prompts for the agent
- check this handler for blocking I/O and rewrite it with async/await
- add type hints to this RequestHandler following the tornado rule
- give me a BaseHandler with a shared HTTPError response instead of try/except in every method
How to install tornado
Manually: put the files in place
.cursor/rules/tornado.mdcFrontmatter: description, globs, alwaysApply
Manually: put the files in place
.claude/rules/tornado.mdThe paths frontmatter field limits the files: move globs from the source into paths
AGENTS.md
Codex reads AGENTS.md: paste the rule text there
Manually: put the files in place
.github/instructions/tornado.instructions.mdThe applyTo field sets which files it applies to: move globs from the source into applyTo
Manually: put the files in place
.devin/rules/tornado.mdManually: put the files in place
.clinerules/tornado.mdStep by step, with commands for each platform: Cursor rules: .mdc files, four modes and what replaced .cursorrules
Questions about tornado
How do I install the tornado rule in Cursor?
Create .cursor/rules/tornado.mdc in your project root and paste the rule contents into it.
What does the tornado rule do?
It tells Cursor how to write Tornado code: async/await instead of blocking calls, full type annotations, and centralized error handling.
Which files does the rule cover?
It declares the glob **/*.py, so every Python file in the project.
Source text
tornado.mdc · CC0-1.0
---
description: Definitive guidelines for writing high-performance, secure, and maintainable Tornado applications using modern Python 3.9+ async/await patterns and best practices.
globs: **/*.py
---
# tornado Best Practices
Tornado is a powerful, non-blocking web framework ideal for high-concurrency applications, WebSockets, and long-polling. These rules enforce modern (Python 3.9+, 2025 standards) best practices, ensuring your code is performant, secure, and maintainable.
## 1. Embrace `async/await` for All I/O
Always use `async def` and `await` for any I/O-bound operations. Avoid older callback-based APIs. Tornado integrates seamlessly with `asyncio`.
❌ BAD: Blocking I/O in a handler
```python
import time
import tornado.web
class BadHandler(tornado.web.RequestHandler):
def get(self) -> None:
time.sleep(1) # Blocks the IOLoop
self.write("Hello, blocked world!")
```
✅ GOOD: Asynchronous I/O
```python
import asyncio
import tornado.web
class GoodHandler(tornado.web.RequestHandler):
async def get(self) -> None:
await asyncio.sleep(1) # Non-blocking
self.write("Hello, async world!")
```
## 2. Leverage Type Hints
Utilize full type annotations (`from __future__ import annotations`) for clarity, static analysis, and improved IDE support. Tornado's stubs are well-maintained.
❌ BAD: Untyped handler
```python
class UntypedHandler(tornado.web.RequestHandler):
def post(self):
name = self.get_argument("name")
self.write(f"Hello, {name}")
```
✅ GOOD: Fully typed handler
```python
from __future__ import annotations
import tornado.web
class TypedHandler(tornado.web.RequestHandler):
async def post(self) -> None:
name: str = self.get_argument("name")
self.write(f"Hello, {name}")
```
## 3. Centralized Error Handling
Let Tornado's built-in error handling for malformed requests (e.g., `multipart-form-data`, invalid headers) propagate. Implement a custom `ErrorHandler` for consistent responses.
❌ BAD: Ignoring or manually handling low-level header errors
```python
# This is an anti-pattern; Tornado handles these automatically.
# Do not try to catch exceptions for malformed headers or multipart data
# directly in every handler. Let it propagate.
```
✅ GOOD: Custom `HTTPError` handler
```python
from __future__ import annotations
import tornado.web
import json
class BaseHandler(tornado.web.RequestHandler):
© sanjeed5 · CC0-1.0 · sanjeed5/awesome-cursor-rules-mdc