Skip to main content

Automatic string literal wrapping for PEP 8 E501 compliance

Project description

e501-fixer

Python 3.10+ License: MIT

Automatic string literal wrapping for PEP 8 E501 compliance.

Problem

PEP 8 recommends a maximum line length of 88 characters. When strings exceed this limit, Python developers must manually wrap them—a tedious, error-prone process. While tools like Black and ruff exist, none provide comprehensive automatic wrapping of string literals.

e501-fixer fills this gap with a safe, well-tested solution that automatically wraps long strings using Python's implicit string concatenation.

Features

  • Automatic string wrapping using implicit concatenation
  • Preserves quote style (single vs. double quotes)
  • Handles all string types (regular, raw, byte strings)
  • Safe by default (skips f-strings and triple-quoted strings)
  • CLI interface for easy integration into workflows
  • Pre-commit hook support for automated checks
  • 100% test coverage with comprehensive test suite
  • Type-safe with full mypy strict mode compliance

Installation

Via pip (when published to PyPI)

pip install e501-fixer

From source (development)

Clone the standalone e501-fixer repository:

git clone https://github.com/muunkky/e501-fixer.git
cd e501-fixer
pip install -e .

With CLI support

pip install -e ".[cli]"

Quick Start

CLI Usage

# Fix E501 violations in a file
e501-fixer fix myfile.py

# Fix violations in a directory
e501-fixer fix src/

# Check for violations without fixing
e501-fixer check myfile.py

# Check with custom line length
e501-fixer fix --max-line-length 100 myfile.py

Python API

from e501_fixer import FileProcessor
from pathlib import Path

# Create processor with custom line length
processor = FileProcessor(max_line_length=100)

# Process single file
result = processor.process_file(Path("example.py"))
print(f"Fixed {result.fixes_applied} violations")

# Process directory
result = processor.process_directory(Path("src/"))
print(f"Fixed {result.total_fixes} violations in {result.files_processed} files")

How It Works

Before

def greet(name: str) -> None:
    message = "Hello, this is a very long string that exceeds the PEP 8 line length limit and needs to be wrapped"
    print(message)

After

def greet(name: str) -> None:
    message = (
        "Hello, this is a very long string that exceeds the "
        "PEP 8 line length limit and needs to be wrapped"
    )
    print(message)

Examples

Preserving Quote Style

# Input: single quotes
description = 'This is a long single-quoted string that needs wrapping and is quite verbose'

# Output: single quotes preserved
description = (
    'This is a long single-quoted string that needs wrapping '
    'and is quite verbose'
)

Respecting Indentation

# Input: nested string
def setup():
    if True:
        config = "This is a very long configuration string that exceeds the maximum line length and must be wrapped properly"

# Output: indentation respected
def setup():
    if True:
        config = (
            "This is a very long configuration string that exceeds "
            "the maximum line length and must be wrapped properly"
        )

Raw Strings

# Input: raw string
pattern = r'This is a very long regex pattern that exceeds the line length and needs to be wrapped for readability'

# Output: raw string type preserved
pattern = (
    r'This is a very long regex pattern that exceeds the line '
    r'length and needs to be wrapped for readability'
)

Pre-commit Integration

Add to .pre-commit-config.yaml:

- repo: local
  hooks:
    - id: e501-fixer
      name: e501-fixer
      entry: e501-fixer fix
      language: system
      types: [python]
      stages: [commit]

Or using the pre-commit hooks defined in this package (when published):

- repo: https://github.com/muunkky/e501-fixer
  rev: v0.1.0
  hooks:
    - id: e501-fix      # Auto-fix violations
    - id: e501-check    # Check without modifying (for CI)

The package provides two hooks:

  • e501-fix: Automatically fixes E501 violations (use before commit)
  • e501-check: Reports violations without modifying (use in CI/CD)

Safety Guarantees

  • No Code Corruption: Conservative approach—skips uncertain cases
  • Preserves Semantics: Implicit concatenation produces identical behavior
  • Type Safe: Full mypy strict mode compliance
  • Well Tested: 90+ tests covering all string types and edge cases
  • Documented: Comprehensive architecture documentation (ADR-018)

Architecture

The tool is built on a modular, TDD-driven architecture:

  • StringLiteralParser: Identifies and extracts string literals using regex
  • BreakPointFinder: Calculates optimal positions to split strings
  • StringWrapper: Applies wrapping transformations
  • FileProcessor: Orchestrates parsing, wrapping, and file I/O

For detailed architecture, see ARCHITECTURE.md.

Performance

  • Per-file: ~1-2ms for average files (100-200 lines)
  • Large files: <100ms for 1000+ line files
  • Directory processing: Efficient batch handling

Configuration

Line Length

e501-fixer fix --max-line-length 100 myfile.py

Python API:

processor = FileProcessor(max_line_length=100)

Indentation

processor = FileProcessor(default_indentation="  ")  # 2 spaces

Limitations

  • F-strings: Not wrapped (interpolations make splitting risky)
  • Triple-quoted strings: Not wrapped (complex semantics)
  • Unbreakable strings: Strings without spaces cannot be wrapped

These are conservative choices that prioritize safety over coverage.

Troubleshooting

No violations found

  • Verify the file has strings exceeding the max line length
  • Check --max-line-length setting (default: 88)
  • Some strings may be intentionally unbreakable (no spaces)

Pre-commit hook not executing

  • Ensure e501-fixer is installed in the pre-commit environment
  • Check .pre-commit-config.yaml syntax
  • Run pre-commit install to activate hooks

Import errors

  • Install CLI dependencies: pip install e501-fixer[cli]
  • Verify Python 3.10+ is installed

Development

Setup

pip install -e ".[dev]"

Testing

pytest tests/
pytest --cov=e501_fixer

Type Checking

mypy e501_fixer/

Linting

ruff check e501_fixer/

License

MIT - see LICENSE file

Contributing

Contributions are welcome! Please ensure:

  • All tests pass (pytest)
  • Code passes type checking (mypy)
  • Code passes linting (ruff check)
  • New features include tests and documentation

References

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

e501_fixer-0.1.0.tar.gz (18.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

e501_fixer-0.1.0-py3-none-any.whl (15.7 kB view details)

Uploaded Python 3

File details

Details for the file e501_fixer-0.1.0.tar.gz.

File metadata

  • Download URL: e501_fixer-0.1.0.tar.gz
  • Upload date:
  • Size: 18.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.8

File hashes

Hashes for e501_fixer-0.1.0.tar.gz
Algorithm Hash digest
SHA256 ebade9dabd80a638c876cd4eb40220ec63bc44f513453e7bf09b069bb29b1897
MD5 702ab7deb6bce079b0347595dc9fa307
BLAKE2b-256 74240660943fcbafe8e43232278bd26412423d71d58f3e1020e61884bb46573a

See more details on using hashes here.

File details

Details for the file e501_fixer-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: e501_fixer-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 15.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.8

File hashes

Hashes for e501_fixer-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8c948c653be312a3e698732768e3c01fbe57219edaa027fdc4647360fcbbb389
MD5 5e1d007a6533ac82e17b4a6898dc1bac
BLAKE2b-256 73664bcaabf88a1cbb24984df6957de2fb33fe0a7cbcebab25907ecf3894de9f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page