Writing and linting Python at scale

Meta’s work on Fixit 2, an auto-fixing Python linter built on libcst, prompts a broader look at how Python can be made to work at large scale through stronger tooling, type annotations and automated code transformation. Commenters contrast Python’s growing static-typing ecosystem and linters (including Ruff and Fixit) with languages like TypeScript and C#, debating whether dynamic languages are suitable foundations for large systems or merely propped up by “band‑aid” tooling. Others focus on practical trade-offs: Python’s ease of debugging and rapid development versus its performance limits, threading issues, and the uneven quality of type hints and libraries in real-world codebases.

Context & Tools Discussed

  • Thread centers on Meta’s Fixit 2 Python linter, built on libcst, and broader experiences with Python linting and typing at scale.
  • Fixit 2’s notable feature: lint rules that can auto-apply code changes, not just report issues.

Trust and Workflow for Auto-Fixing Linters

  • Some are wary of linters that auto-change code beyond formatting/imports.
  • Others point to ecosystems like C#/.NET, ESLint, and Rubocop where auto-fix is standard and productive, especially when:
    • Fixes are applied post-commit or via code review with explicit acceptance.
    • Only “safe” categories of fixes are auto-applied.
  • Suggested workflow: commit first, run auto-fix, then inspect diff.

Ruff vs Flake8 and Other Linters

  • Ruff praised for:
    • Very high speed.
    • Consolidating formatting, linting, and import ordering in one tool.
    • Catching issues that some flake8 plugins miss.
  • Criticisms:
    • Inconsistent with original flake8 plugins on large, messy legacy codebases.
    • Some auto-fixes previously introduced new issues; newer Ruff versions distinguish “safe” vs “unsafe” fixes.
  • Ruff maintainers (in-thread) say:
    • They aim for equal or better correctness than plugins and welcome bug reports.
    • Lint/fix is iterative until no more fixable issues remain.
  • Several commenters report successful adoption of Ruff across many projects with few problems.

Python at Scale: Dynamic vs Static Typing

  • Strong disagreement over whether Python (and similar “dynamic scripting languages”) are suitable for large systems:
    • Critics: large companies end up recreating static typing and heavy tooling; static languages now prototype fast enough that starting with dynamic languages is a mistake.
    • Defenders: Python’s optional type system, sum types, pattern matching, and external checkers make it viable and increasingly “safe.”
  • Long subthread debates terminology (“dynamic language”, “dynamic typing”) and type-theory details: recursive types (JSON), variadic generics, tuple concatenation, and comparison to TypeScript and Haskell.

Python’s Strengths and Weaknesses

  • Proponents highlight:
    • Ease of debugging and clear runtime errors.
    • Good syntax and suitability for teaching.
    • Type annotations improving scalability of large codebases.
  • Critics argue:
    • Python is never the “best” tool on engineering merits; popularity and band-aid tooling dominate.
    • Performance and threading (GIL) remain real scaling limits; workarounds often involve subprocesses.

Desire for Unified Tooling

  • Some want a single tool handling formatting, linting, sorting, and pre-commit checks, caring more about consistency than style specifics.
  • Ruff is seen as a promising candidate; its funding is viewed as a potential accelerant toward “one-tool” coherence, including possibly replacing the current fragmented pre-commit ecosystem.