CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-darker

Apply Black formatting only in regions changed since last commit

Pending
Overview
Eval results
Files

preprocessors.mddocs/

Pre-processors

Integration with code pre-processors like isort for import sorting and flynt for f-string conversion, applied before main formatting.

Capabilities

Import Sorting with isort

Integration with isort for organizing and sorting Python import statements.

def apply_isort(
    content: TextDocument,
    src: Tuple[str, ...],
    config: str,
) -> TextDocument:
    """
    Run isort on Python source file content to organize imports.
    
    Parameters:
    - content: Source code content to process
    - src: Source file/directory paths for configuration context
    - config: Path to configuration file
    
    Returns:
    Source code with sorted and organized imports
    
    Note:
    Requires isort to be installed. If not available, returns content unchanged.
    """

isort: Optional[ModuleType]
"""
Optional isort module reference.
None if isort is not installed, otherwise the imported isort module.
"""

class IsortArgs(TypedDict, total=False):
    """Command line arguments for isort configuration."""
    profile: str                    # isort profile (e.g., "black")
    multi_line_output: int         # Multi-line import output mode
    line_length: int               # Maximum line length
    known_first_party: List[str]   # First-party package names
    known_third_party: List[str]   # Third-party package names
    force_single_line: bool        # Force single-line imports
    combine_as_imports: bool       # Combine 'import x' and 'from x import y'
    include_trailing_comma: bool   # Add trailing comma to multi-line imports

F-string Conversion with flynt

Integration with flynt for converting old-style string formatting to f-strings.

def apply_flynt(
    content: TextDocument,
    line_length: int,
) -> TextDocument:
    """
    Run flynt on Python source file content to convert to f-strings.
    
    Converts old-style % formatting and .format() calls to f-string literals
    where possible and safe.
    
    Parameters:
    - content: Source code content to process
    - line_length: Maximum line length for formatting decisions
    
    Returns:
    Source code with f-string conversions applied
    
    Note:
    Requires flynt to be installed. If not available, returns content unchanged.
    """

flynt: Optional[ModuleType]
"""
Optional flynt module reference.
None if flynt is not installed, otherwise the imported flynt module.
"""

Usage Examples

Basic Import Sorting

from darker.import_sorting import apply_isort, isort
from darkgraylib.utils import TextDocument

# Check if isort is available
if isort is not None:
    print("isort is available for import sorting")
else:
    print("isort not installed - install with: pip install darker[isort]")

# Apply import sorting
source_code = TextDocument.from_lines([
    "import os",
    "from typing import List",
    "import sys",
    "from mypackage import mymodule",
    "",
    "def main():",
    "    pass"
])

sorted_code = apply_isort(
    content=source_code,
    src=("src/",),
    config="pyproject.toml"
)

print("Sorted imports:")
print(sorted_code.string)

F-string Conversion

from darker.fstring import apply_flynt, flynt
from darkgraylib.utils import TextDocument

# Check if flynt is available
if flynt is not None:
    print("flynt is available for f-string conversion")
else:
    print("flynt not installed - install with: pip install darker[flynt]")

# Apply f-string conversion
source_code = TextDocument.from_lines([
    'name = "World"',
    'message = "Hello, {}!".format(name)',
    'count = 42',
    'status = "Processing %d items" % count',
    '',
    'print(message)',
    'print(status)'
])

converted_code = apply_flynt(
    content=source_code,
    line_length=88
)

print("Converted to f-strings:")
print(converted_code.string)
# Expected output would show f-string conversions:
# message = f"Hello, {name}!"
# status = f"Processing {count} items"

Integration with Main Workflow

from darker.import_sorting import apply_isort
from darker.fstring import apply_flynt
from darker.formatters import create_formatter
from darkgraylib.utils import TextDocument

def apply_all_preprocessing(
    content: TextDocument,
    use_isort: bool = True,
    use_flynt: bool = True,
    line_length: int = 88
) -> TextDocument:
    """Apply all pre-processing steps in the correct order."""
    
    result = content
    
    # Step 1: Sort imports (if enabled)
    if use_isort:
        result = apply_isort(
            content=result,
            src=("src/",),
            config="pyproject.toml"
        )
    
    # Step 2: Convert to f-strings (if enabled)
    if use_flynt:
        result = apply_flynt(
            content=result,
            line_length=line_length
        )
    
    # Step 3: Apply main formatter (Black, Ruff, etc.)
    formatter = create_formatter("black")
    config = formatter.read_config(("src/",), "pyproject.toml")
    result = formatter.run(result, config)
    
    return result

# Usage
source = TextDocument.from_lines([
    "import sys",  
    "from typing import Dict",
    "import os",
    "",
    "def greet(name):",
    '    return "Hello {}".format(name)',
])

processed = apply_all_preprocessing(source)
print(processed.string)

Configuration Examples

pyproject.toml Configuration

# isort configuration
[tool.isort]
profile = "black"
multi_line_output = 3
line_length = 88
known_first_party = ["mypackage"]
known_third_party = ["requests", "pandas"]
include_trailing_comma = true
force_grid_wrap = 0
use_parentheses = true
ensure_newline_before_comments = true

# flynt configuration (if supported by your version)
[tool.flynt]
line_length = 88

Programmatic Configuration

from darker.import_sorting import IsortArgs

# Configure isort programmatically
isort_config: IsortArgs = {
    'profile': 'black',
    'multi_line_output': 3, 
    'line_length': 88,
    'known_first_party': ['mypackage', 'myutil'],
    'known_third_party': ['requests', 'click'],
    'force_single_line': False,
    'combine_as_imports': True,
    'include_trailing_comma': True,
}

# This would typically be handled by apply_isort reading from config file

Error Handling and Optional Dependencies

from darker.import_sorting import apply_isort, isort
from darker.fstring import apply_flynt, flynt
from darkgraylib.utils import TextDocument

def safe_preprocess(content: TextDocument) -> TextDocument:
    """Safely apply preprocessing with fallbacks for missing dependencies."""
    
    result = content
    
    # Try isort if available
    try:
        if isort is not None:
            result = apply_isort(result, ("src/",), "pyproject.toml")
            print("Applied isort import sorting")
        else:
            print("Skipping isort - not installed")
    except Exception as e:
        print(f"isort failed: {e}")
    
    # Try flynt if available
    try:
        if flynt is not None:
            result = apply_flynt(result, 88)
            print("Applied flynt f-string conversion")
        else:
            print("Skipping flynt - not installed")
    except Exception as e:
        print(f"flynt failed: {e}")
    
    return result

# Usage
source = TextDocument.from_str("import sys\nimport os\n")
processed = safe_preprocess(source)

Custom Pre-processor Integration

from darkgraylib.utils import TextDocument
from typing import Callable

PreprocessorFunc = Callable[[TextDocument], TextDocument]

def create_preprocessing_pipeline(*preprocessors: PreprocessorFunc) -> PreprocessorFunc:
    """Create a pipeline of preprocessing functions."""
    
    def pipeline(content: TextDocument) -> TextDocument:
        result = content
        for preprocessor in preprocessors:
            try:
                result = preprocessor(result)
            except Exception as e:
                print(f"Preprocessor {preprocessor.__name__} failed: {e}")
        return result
    
    return pipeline

# Example usage
def my_custom_preprocessor(content: TextDocument) -> TextDocument:
    """Custom preprocessing step."""
    lines = [line.rstrip() for line in content.lines]  # Remove trailing whitespace
    return TextDocument.from_lines(lines)

# Create pipeline
pipeline = create_preprocessing_pipeline(
    lambda c: apply_isort(c, ("src/",), "pyproject.toml"),
    my_custom_preprocessor,
    lambda c: apply_flynt(c, 88),
)

# Apply pipeline
result = pipeline(source_content)

Install with Tessl CLI

npx tessl i tessl/pypi-darker@3.0.1

docs

chooser.md

command-line.md

configuration.md

diff-utilities.md

file-utilities.md

formatters.md

git-integration.md

index.md

main-functions.md

preprocessors.md

verification.md

tile.json