Thread Safety Analyzer
A multi-language static analysis tool for detecting concurrency and thread safety issues. Use it locally as a linter, in CI pipelines, or to generate context for LLM-assisted PR reviews.
Installation
pip install thread-safety
Or install from source:
git clone https://github.com/steph-dove/thread-safe-check.git
cd thread-safe-check
pip install -e .
Use Cases
Local Development (Linter)
Run as a linter during development to catch concurrency issues early:
# Analyze your project
thread-safety analyze ./src
# Check only files you've changed
thread-safety analyze . --git-diff
# Focus on critical issues
thread-safety analyze ./src --min-severity high
CI/CD Integration
Add to your CI pipeline to catch thread safety issues before merge.
GitHub Actions:
- name: Thread Safety Check
run: |
pip install thread-safety
thread-safety analyze ./src --output json -f thread-safety-report.json
- name: Upload Report
uses: actions/upload-artifact@v3
with:
name: thread-safety-report
path: thread-safety-report.json
GitLab CI:
thread-safety:
script:
- pip install thread-safety
- thread-safety analyze ./src --min-severity medium
allow_failure: true # Start as warning-only
Pre-commit Hook:
# .pre-commit-config.yaml
repos:
- repo: local
hooks:
- id: thread-safety
name: Thread Safety Check
entry: thread-safety analyze
language: system
files: \.(py|js|ts|go|rs)$
pass_filenames: false
LLM PR Review Context
Generate rich context for AI-assisted code review:
# Generate LLM-optimized output
thread-safety analyze ./src --output llm
# Analyze only changed files for PR review
thread-safety analyze . --git-diff --output llm
The LLM output format includes:
- Code snippets with context
- Detailed explanations of why each issue matters
- Suggested fixes with before/after examples
- Severity and category information
Quick Start
# Analyze a directory
thread-safety analyze ./src
# Output formats
thread-safety analyze ./src --output text # Human-readable (default)
thread-safety analyze ./src --output json # For CI/tooling
thread-safety analyze ./src --output markdown # For documentation
thread-safety analyze ./src --output llm # For AI review
# Filter by severity (info, low, medium, high, critical)
thread-safety analyze ./src --min-severity high
# Run specific rules only
thread-safety analyze ./src --rule TS001 --rule TS010
# Analyze only git-changed files
thread-safety analyze . --git-diff
# Save report to file
thread-safety analyze ./src --output json -f report.json
# List all available rules
thread-safety rules
# Generate config file
thread-safety init
Detection Rules
Shared Mutable State
- TS001: Global variable mutation in threaded context
- TS002: Class attribute mutation across threads
- TS003: Closure capturing mutable variable
- TS004: Module-level mutable default argument
Race Conditions
- TS010: Unprotected shared variable access
- TS011: Check-then-act (TOCTOU)
- TS012: Compound operation without lock
- TS013: Collection modification during iteration
Lock Issues
- TS020: Potential deadlock (inconsistent lock ordering)
- TS021: Lock acquired but never released
- TS022: Double lock acquisition (non-reentrant)
- TS023: Lock held during blocking I/O
Async Patterns
- TS030: Blocking call in async function
- TS031: Missing await on coroutine
- TS032: Using threading.Lock in async code
- TS033: Shared mutable state in coroutine
- TS034: Sync primitive in async context
Supported Languages
| Language | Status | Rules | Notes |
|---|---|---|---|
| Python | ✅ Stable | 17 | Full coverage |
| JavaScript/TypeScript | ✅ Stable | 8 | Async/Promise patterns |
| Go | ✅ Stable | 5 | Goroutines, sync.Mutex |
| Rust | ✅ Stable | 8 | Async, std::sync |
| Java | Planned | - | - |
Language Support Matrix
| Rule | Python | JS/TS | Go | Rust |
|---|---|---|---|---|
| TS001 Global Mutation | ✅ | - | - | - |
| TS002 Class Attribute | ✅ | - | - | - |
| TS003 Closure Capture | ✅ | ✅ | ✅ | ✅ |
| TS004 Mutable Default | ✅ | - | - | - |
| TS010 Unprotected Access | ✅ | - | - | - |
| TS011 Check-Then-Act | ✅ | ✅ | ✅ | ✅ |
| TS012 Compound Operation | ✅ | - | - | - |
| TS013 Collection Iteration | ✅ | ✅ | ✅ | ✅ |
| TS020 Deadlock | ✅ | - | ✅ | ✅ |
| TS021 Lock Not Released | ✅ | - | - | - |
| TS022 Double Lock | ✅ | - | - | - |
| TS023 Lock Blocking I/O | ✅ | - | ✅ | ✅ |
| TS030 Blocking in Async | ✅ | ✅ | - | ✅ |
| TS031 Missing Await | ✅ | ✅ | - | ✅ |
| TS032 Threading Lock in Async | ✅ | - | - | - |
| TS033 Shared State in Coroutine | ✅ | ✅ | - | ✅ |
| TS034 Sync Primitive in Async | ✅ | - | - | - |
Configuration
Create a thread-safety.toml file in your project root:
[thread-safety]
include = ["src", "lib"]
exclude = ["**/node_modules/**", "**/.venv/**", "**/test/**"]
min_severity = "medium"
[thread-safety.rules]
# Enable only specific rules
enable = ["TS001", "TS010", "TS020"]
# Or disable specific rules
disable = ["TS004"]
Output Formats
Text (default)
Human-readable output for terminal with colors and code snippets.
JSON
Structured output for CI/CD integration and tooling:
thread-safety analyze ./src --output json -f report.json
Markdown
Documentation-friendly format for reports:
thread-safety analyze ./src --output markdown -f report.md
LLM
Optimized for AI-assisted code review with rich context:
thread-safety analyze ./src --output llm
Example Output
Found 2 issue(s):
■ TS030 src/api/handler.py:45:4
Blocking call 'requests.get' in async function 'fetch_data'
43 | async def fetch_data(url: str):
44 | # This blocks the event loop!
> 45 | response = requests.get(url)
46 | return response.json()
Suggestion: Replace with async alternative: aiohttp or httpx
■ TS013 src/cache.py:23:8
Collection 'items' modified with 'pop' during iteration
21 | for key in cache.items:
22 | if is_expired(key):
> 23 | cache.items.pop(key)
24 |
Suggestion: Collect keys to remove first, then remove outside the loop
Development
# Install with dev dependencies
pip install -e ".[dev]"
# Run tests
pytest
# Run linting
ruff check src tests
# Type checking
mypy src
License
MIT
Release files for thread-safety 0.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| thread_safety-0.4.0.tar.gz | 60.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| thread_safety-0.4.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 149.7 kB
Release files / thread_safety-0.4.0.tar.gz
| Download URL | thread_safety-0.4.0.tar.gz |
|---|---|
| Size | 60.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
778244f825472f7e16f87782f9301a6185691d2f59399700118c2eed6a135bbd
|
|
BLAKE2b-256 checksum How to use checksums |
a79e9a28e140b244a43a50c5fc5e6c0db53f766d2a144398bde221d707084de8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.2
|
Release files / thread_safety-0.4.0-py3-none-any.whl
| Download URL | thread_safety-0.4.0-py3-none-any.whl |
|---|---|
| Size | 89.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
40a9556641227c1c5895eb121aab65d224f0938e42a8363121171050be08142d
|
|
BLAKE2b-256 checksum How to use checksums |
e66b2d8a2a9dcf92fa62db019aac7c4e7bf0d94c25b365b0136d61fc6355af6a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.2
|