惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Webroot Blog
Webroot Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
SecWiki News
SecWiki News
S
Secure Thoughts
V2EX - 技术
V2EX - 技术
T
Tor Project blog
H
Hacker News: Front Page
P
Privacy International News Feed
Google DeepMind News
Google DeepMind News
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Recent Commits to openclaw:main
Recent Commits to openclaw:main
V
Vulnerabilities – Threatpost
C
CERT Recently Published Vulnerability Notes
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
C
Cyber Attacks, Cyber Crime and Cyber Security
Help Net Security
Help Net Security
D
Darknet – Hacking Tools, Hacker News & Cyber Security
H
Heimdal Security Blog
AI
AI
PCI Perspectives
PCI Perspectives
Cyberwarzone
Cyberwarzone
P
Privacy & Cybersecurity Law Blog
AWS News Blog
AWS News Blog
Attack and Defense Labs
Attack and Defense Labs
The Last Watchdog
The Last Watchdog
K
Kaspersky official blog
T
The Exploit Database - CXSecurity.com
C
CXSECURITY Database RSS Feed - CXSecurity.com
Security Latest
Security Latest
Schneier on Security
Schneier on Security
Scott Helme
Scott Helme
L
Lohrmann on Cybersecurity
Cisco Talos Blog
Cisco Talos Blog
The Hacker News
The Hacker News
N
News and Events Feed by Topic
S
Schneier on Security
Simon Willison's Weblog
Simon Willison's Weblog
F
Fortinet All Blogs
T
Threatpost
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
V
V2EX
博客园 - 三生石上(FineUI控件)
WordPress大学
WordPress大学
Apple Machine Learning Research
Apple Machine Learning Research
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
云风的 BLOG
云风的 BLOG
博客园_首页
Recent Announcements
Recent Announcements
G
Google Developers Blog
Martin Fowler
Martin Fowler

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
Your Python Pre-commit Hook Took 18 Seconds. Ruff Does It in 0.3.
Shayan Holakouee · 2026-06-03 · via DEV Community

Here is a pre-commit hook I used to have:

black .
isort .
flake8 .
pylint src/

Enter fullscreen mode Exit fullscreen mode

Four tools. Four configs. Four things that could break. And on a mid-sized project, about 18 seconds of waiting every time I committed.

Now I have this:

ruff check . --fix
ruff format .

Enter fullscreen mode Exit fullscreen mode

Two commands. One tool. 0.3 seconds. Same coverage, fewer headaches.

That tool is Ruff, and if you're still running the old stack, this article will convince you to switch.


What Is Ruff?

Ruff is a Python linter and formatter written in Rust. It was built by Astral, the same team behind uv. The pitch is simple: replace Flake8, Black, isort, pyupgrade, and autoflake with one binary that runs 10 to 100 times faster than any of them individually.

It's not a wrapper around those tools. Ruff re-implements their rules directly in Rust, which is why it's so fast and why it has no Python dependencies at all.

As of 2025, Ruff ships with over 900 lint rules. It's used in production by NumPy, Pandas, FastAPI, Airflow, and thousands of other projects.


Installing Ruff

# Via pip
pip install ruff

# Via uv (recommended)
uv add --dev ruff

# Standalone binary (no Python required)
curl -LsSf https://astral.sh/ruff/install.sh | sh

Enter fullscreen mode Exit fullscreen mode

Check it works:

ruff --version
# ruff 0.x.x

Enter fullscreen mode Exit fullscreen mode


The Two Commands You'll Use Every Day

Ruff has two main modes: check (linting) and format (formatting).

# Lint your code
ruff check .

# Lint and auto-fix what can be fixed
ruff check . --fix

# Format your code (Black-compatible)
ruff format .

# Check formatting without changing files
ruff format . --check

Enter fullscreen mode Exit fullscreen mode

That's the whole surface area for day-to-day use. Everything else is configuration.


What Does It Actually Catch?

Let's take a messy file:

import os
import sys
import json

def greet(name):
    x = 42
    if name == None:
        return "nobody"
    msg = "Hello, %s" % name
    return msg

Enter fullscreen mode Exit fullscreen mode

Run ruff check messy.py:

messy.py:3:1: F401 `json` imported but unused
messy.py:6:5: F841 Local variable `x` is assigned to but never used
messy.py:7:12: E711 Comparison to `None` (use `is None`)
messy.py:8:11: UP031 Use f-string instead of `%`-formatting
Found 4 errors.

Enter fullscreen mode Exit fullscreen mode

Now run ruff check messy.py --fix and look at the result:

import os
import sys


def greet(name):
    if name is None:
        return "nobody"
    msg = f"Hello, {name}"
    return msg

Enter fullscreen mode Exit fullscreen mode

Unused import removed. == None fixed to is None. %-formatting upgraded to an f-string. All automatically.

The x = 42 unused variable is flagged but not auto-fixed because removing a variable assignment could theoretically change behavior in edge cases. Ruff is conservative about what it touches automatically.


Replacing isort

Import sorting is built in. No separate tool, no separate config.

# Before
import sys
import os
from collections import defaultdict
import json
from typing import Optional

Enter fullscreen mode Exit fullscreen mode

# After ruff check . --fix
import json
import os
import sys
from collections import defaultdict
from typing import Optional

Enter fullscreen mode Exit fullscreen mode

Standard library, third-party, and local imports get grouped and sorted correctly. Same behavior as isort, no extra setup.

Enable it explicitly in your config if it's not running by default:

[tool.ruff.lint]
select = ["I"]  # isort rules

Enter fullscreen mode Exit fullscreen mode


Configuration in pyproject.toml

Ruff reads from pyproject.toml, which means no separate .flake8, .isort.cfg, or setup.cfg. One file rules everything.

A solid starting config:

[tool.ruff]
line-length = 88
target-version = "py311"

[tool.ruff.lint]
select = [
    "E",    # pycodestyle errors
    "W",    # pycodestyle warnings
    "F",    # pyflakes
    "I",    # isort
    "B",    # flake8-bugbear
    "UP",   # pyupgrade
    "RUF",  # ruff-specific rules
]
ignore = [
    "E501",  # line too long (handled by formatter)
]

[tool.ruff.format]
quote-style = "double"
indent-style = "space"

Enter fullscreen mode Exit fullscreen mode

The select field is where you pick which rule categories to enable. By default Ruff only runs E and F rules, which is already solid coverage. Adding B (bugbear) and UP (pyupgrade) gets you a lot more value with very little noise.


Rule Categories Worth Knowing

Ruff organizes its 900+ rules into prefixed categories. Here are the ones worth enabling on most projects:

Prefix Origin What It Catches
F Pyflakes Unused imports, undefined names, redefined vars
E / W pycodestyle PEP 8 style issues
I isort Import ordering
B flake8-bugbear Common bugs and design issues
UP pyupgrade Outdated syntax (pre-f-strings, old union types)
N pep8-naming Naming conventions
RUF Ruff-native Rules with no upstream equivalent
SIM flake8-simplify Code that can be simplified
ANN flake8-annotations Missing type annotations

You can look up any rule at docs.astral.sh/ruff/rules. Each one has an explanation and an example.


Ignoring Rules Inline

Sometimes you genuinely need to break a rule. The syntax is the same as Flake8:

import os  # noqa: F401

Enter fullscreen mode Exit fullscreen mode

Or disable for an entire block:

# ruff: noqa: E501
some_very_long_string = "this line is intentionally long because it has to be"

Enter fullscreen mode Exit fullscreen mode

Or skip formatting for a section:

# fmt: off
matrix = [
    1, 0, 0,
    0, 1, 0,
    0, 0, 1,
]
# fmt: on

Enter fullscreen mode Exit fullscreen mode


Editor Integration

VS Code

Install the Ruff extension and add this to your settings:

{
  "editor.formatOnSave": true,
  "editor.defaultFormatter": "charliermarsh.ruff",
  "[python]": {
    "editor.codeActionsOnSave": {
      "source.fixAll.ruff": "explicit",
      "source.organizeImports.ruff": "explicit"
    }
  }
}

Enter fullscreen mode Exit fullscreen mode

Format on save, import sort on save, lint feedback in the gutter. Done.

Neovim

Via conform.nvim and nvim-lint, or through the LSP with nvim-lspconfig. The Ruff LSP server (ruff server) ships with the Ruff binary.


Pre-commit Integration

This is where Ruff's speed makes the biggest practical difference. Replace your old hooks with:

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/astral-sh/ruff-pre-commit
    rev: v0.9.0
    hooks:
      - id: ruff
        args: [--fix]
      - id: ruff-format

Enter fullscreen mode Exit fullscreen mode

Two hooks, no Python dependencies, sub-second feedback. Your teammates will stop disabling pre-commit.


Migrating From the Old Stack

If you're coming from Black + isort + Flake8, the migration path is low-friction.

Ruff's formatter is designed to be Black-compatible, so your diffs should be minimal after switching. Start by running both and comparing output:

black --check .
ruff format --check .

Enter fullscreen mode Exit fullscreen mode

For linting, start conservative: just enable E, F, and I. Fix the violations, then expand select to add more rule categories as your team is ready.

You can also silence existing violations in bulk without fixing them using # noqa comments or per-file-ignores, which lets you enforce Ruff on new code while leaving legacy files alone.


One Honest Caveat

Ruff does not do type checking. It does not replace mypy or pyright. It can catch some type-annotation issues (via the ANN rules) and enforce annotation style, but it does not perform type inference.

If you want static type checking, you still need mypy or pyright alongside Ruff. They solve different problems.


The Bottom Line

Ruff is not an incremental improvement on Python linting. It's a full reset: one tool, one config file, no dependency conflicts, no wrapper scripts, and feedback fast enough that you stop dreading the pre-commit hook.

If you're starting a new project, add it as a dev dependency on day one and configure it in pyproject.toml. If you're on an existing project, swap in the formatter first since it's Black-compatible and then layer in linting rules from there.

The Python ecosystem moved slowly on tooling for a long time. Ruff is what it looks like when someone decides to stop accepting that.


Enjoyed this? I wrote a similar piece on uv, the package manager from the same team, if you want to go further down the Astral rabbit hole. Drop a reaction or share it with someone still waiting 18 seconds for their pre-commit to finish.