Thanks to visit codestin.com
Credit goes to github.com

Skip to content

kriskimmerle/asyncaudit

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 

Repository files navigation

asyncaudit

Python Async Antipattern Detector — Find blocking calls, event loop misuse, and concurrency bugs in async code. Zero dependencies.

Why?

Tool Deps Blocking Calls Event Loop Concurrency Shared State
asyncaudit 0
flake8-async flake8
pylint-blocking-calls pylint
ruff (ASYNC rules) ruff partial

Quick Start

# Check a project
python asyncaudit.py src/

# With fix suggestions
python asyncaudit.py --verbose src/

# CI mode
python asyncaudit.py --check --threshold 80 src/

# JSON output
python asyncaudit.py --json src/

What It Detects

20 Rules Across 5 Categories

Blocking Calls (8 rules)

Rule Sev Pattern
A01 🔴 time.sleep() in async (blocks event loop)
A02 🔴 Sync file I/O: open(), os.read(), pathlib.Path.read_text()
A03 🔴 Sync HTTP: requests.get(), urllib.request.urlopen()
A04 🔴 subprocess.run() / os.system()
A05 ⚠️ input() blocks event loop
A06 ⚠️ threading.Lock/Semaphore (use asyncio.Lock)
A07 ⚠️ queue.Queue (use asyncio.Queue)
A08 ⚠️ Sync DB: sqlite3.connect, psycopg2.connect

Event Loop (3 rules)

Rule Sev Pattern
A20 🔴 asyncio.run() inside async function (RuntimeError)
A21 ⚠️ asyncio.get_event_loop() deprecated
A22 ℹ️ Manual event loop management

Concurrency (4 rules)

Rule Sev Pattern
A30 ⚠️ Sequential awaits (should use gather())
A31 ⚠️ Unbounded gather() (add semaphore)
A32 ℹ️ Missing timeout on external calls
A33 ⚠️ Fire-and-forget create_task() (task may be GC'd)

Thread/State Safety (2 rules)

Rule Sev Pattern
A40 ℹ️ Creating threads inside async functions
A41 ⚠️ Mutating module-level state without asyncio.Lock

70+ blocking calls detected including requests, urllib, subprocess, os.system, sqlite3, psycopg2, pymysql, pymongo, redis, pathlib, shutil, smtplib, and more.

Example

# ❌ Bad: blocks the event loop
async def fetch_data(url):
    time.sleep(1)                    # A01: use await asyncio.sleep()
    response = requests.get(url)     # A03: use aiohttp/httpx
    with open("cache.json") as f:    # A02: use aiofiles
        cache = json.load(f)
    return response.json()

# ✅ Good: non-blocking
async def fetch_data(url):
    await asyncio.sleep(1)
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            return await response.json()

Options

Flag Description
--check Exit with code 1 if score below threshold
--threshold N Score threshold (default: 80)
--json Output as JSON
--severity LEVEL Min: error, warning, info
--ignore RULES Skip rules (e.g., A02,A05)
--verbose Show fix suggestions
--quiet Only show summary
--list-rules List all rules

Requirements

  • Python 3.9+
  • Zero dependencies

License

MIT

About

Python Async Antipattern Detector — blocking calls, event loop misuse, concurrency bugs. 20 rules, 70+ patterns. Zero deps.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages