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.