Skip to content

4.1. Linting

What is software linting?

Linting is the process of using a static code analysis tool—a "linter"—to check source code for programmatic errors, bugs, stylistic inconsistencies, and other potential issues. It acts as an automated code reviewer, flagging problems without executing the program.

Why are linters essential for development?

Integrating linters into a development workflow provides significant benefits:

  • Enforce Code Quality: Linters automatically enforce coding standards (like PEP 8 for Python), ensuring consistency and maintainability, which is critical for collaborative projects.
  • Enhance Readability: By standardizing style, linters make code easier to read and understand for all team members, streamlining code reviews and onboarding.
  • Prevent Bugs: They detect common errors, such as syntax mistakes, undefined variables, or problematic patterns, catching bugs before they reach production.
  • Accelerate Learning: For developers new to a language or a team, linters provide immediate feedback, helping them learn and adopt best practices quickly.

Ruff is the recommended linter for modern Python projects. It is written in Rust and is exceptionally fast, often hundreds of times faster than other linters like Pylint. Its speed allows for real-time feedback in your editor without impacting performance.

Key advantages of Ruff include: - Speed: Get instant feedback as you write code. - All-in-One: It combines the functionality of multiple tools (e.g., pylint, pyflakes, isort) into a single, cohesive package. - Auto-Fixing: Ruff can automatically fix many of the issues it detects, saving you time and effort. - VS Code Extension: The official Ruff VS Code extension integrates these features directly into your editor.

# Install Ruff into your "check" dependency group
uv add --group check ruff

# Run Ruff to lint your codebase
uv run ruff check src/ tests/

To keep your repository clean, remember to add the .ruff_cache/ directory to your .gitignore file.

How do you configure a linter?

Linter configurations are typically placed in the pyproject.toml file. This allows you to define project-wide rules, customize behavior, and ensure every developer uses the same settings.

Here is a sample configuration for Ruff:

[tool.ruff]
# automatic fix when possible
fix = true
# define the default indent width
indent-width = 4
# define the default line length
line-length = 100
# define the default python version
target-version = "py312"

[tool.ruff.lint.per-file-ignores]
# exceptions for docstrings in tests
"tests/*.py" = ["D100", "D103"]

If you need to ignore a specific rule for a single line, you can use an inline noqa (no quality assurance) comment:

# Ignore the "unused import" error (F401) for this specific line
from project.module import specific_import  # noqa: F401

How does linting differ from formatting?

While often used together, linting and formatting have distinct purposes: - Linting analyzes code for correctness and adherence to quality standards. It catches potential bugs and logical errors. - Formatting focuses purely on style. It automatically rewrites code to enforce consistent layout, spacing, and line breaks, without changing its logic.

Tools like Ruff can perform both linting and formatting, providing a comprehensive solution for code quality and style consistency.

What are the best practices for linting?

  1. Integrate Linting into Your Editor: Configure your IDE or code editor to run the linter automatically, providing immediate feedback as you type.
  2. Automate with Pre-Commit Hooks: Run the linter on staged files before they are committed. This practice catches issues early and keeps the main branch clean.
  3. Enforce Linting in CI/CD: Add a linting step to your Continuous Integration (CI) pipeline to prevent code that violates standards from being merged.
  4. Start with Sensible Defaults: Begin with the linter's default rule set and customize it over time by adding or ignoring rules that fit your project's specific needs.
  5. Use Linting in Code Reviews: Make passing the linter a prerequisite for code review. This allows reviewers to focus on the logic and architecture instead of style debates.
  6. Keep Rules Consistent: Ensure the entire team understands and adheres to the linting configuration to maintain a uniform codebase.

Additional Resources