An open API service indexing awesome lists of open source software.

https://github.com/dhodgson615/lintomatic

A basic linter for Python projects written in Haskell
https://github.com/dhodgson615/lintomatic

developer-tools functional-programming haskell lint linter linters linting python python-3

Last synced: 5 months ago
JSON representation

A basic linter for Python projects written in Haskell

Awesome Lists containing this project

README

          

# lintomatic

A specialized Python linter written in Haskell that focuses on docstring line length and indentation consistency.

## Features

- **Docstring Length Checking**: Identifies lines within Python docstrings that exceed 72 characters
- **Indentation Analysis**: Detects problematic indentation patterns where code dedentation occurs without proper separation
- **Block Statement Blank Lines**: Ensures Python block statements (if, elif, else, for, while, try, except, finally, with, def, class) have blank lines before them for better readability
- **Keyword Statement Separation**: Ensures keyword statements (assert, return, if, etc.) have blank lines separating them from non-keyword statements (assignments, expressions) at module level
- **Recursive Directory Scanning**: Automatically finds and processes all `.py` files in a directory tree
- **Clear Output**: Provides precise line numbers and categorized issue reporting

## Dependencies

### Haskell Environment
- **GHC** (Glasgow Haskell Compiler) version 8.10 or later
- **Cabal** or **Stack** for dependency management (optional, but recommended for development)

### System Requirements
- Unix-like operating system (Linux, macOS)
- Windows (with appropriate Haskell installation)

### Installing Haskell Dependencies

#### Option 1: Using GHCup (Recommended)
```bash
curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh
ghcup install ghc
ghcup install cabal
```

#### Option 2: System Package Manager

**Ubuntu/Debian:**
```bash
sudo apt-get update
sudo apt-get install ghc cabal-install
```

**macOS (Homebrew):**
```bash
brew install ghc cabal-install
```

**Arch Linux:**
```bash
sudo pacman -S ghc cabal-install
```

### Verifying Installation
```bash
ghc --version # Should show version 8.10+
cabal --version # Should show cabal-install version
```

## Installation

### Quick Start
1. Clone the repository:
```bash
git clone https://github.com/dhodgson615/lintomatic.git
cd lintomatic
```

2. Compile the program:
```bash
ghc --make src/lintomatic.hs -o lintomatic
```

3. Run the linter:
```bash
./lintomatic
```

### Alternative Build Methods

#### Using Cabal
```bash
cabal build
cabal run lintomatic
```

#### Using Make (with provided Makefile)
```bash
make # Build the executable
make test # Run quick functionality test
make check-env # Verify Haskell environment
make clean # Clean build artifacts
```

#### Manual Compilation with Optimizations
```bash
ghc -O2 --make src/lintomatic.hs -o lintomatic
```

## Usage

### Basic Usage
Run lintomatic from any directory containing Python files:

```bash
./lintomatic
```

The linter will:
1. Recursively find all `.py` files in the current directory
2. Check each file for docstring line length, indentation issues, and block statement formatting
3. Report findings with specific line numbers

### Example Output
```
File: src/example.py
Docstring lines exceeding 72 characters:
Line 15
Line 23
Lines with problematic indentation:
Line 45
Block statements missing blank lines above:
Line 12
Line 34
Keyword statements missing blank lines from non-keyword statements:
Line 18
Line 28

File: tests/test_module.py
Docstring lines exceeding 72 characters:
Line 8
```

### Command Line Options
Currently, lintomatic runs with default settings:
- Maximum docstring line length: 72 characters
- Scans from current directory recursively

## Test Cases

### Manual Testing

Create test files to verify functionality:

#### Test 1: Docstring Length Issues
Create `test_docstring.py`:
```python
"""
This is a very long docstring line that definitely exceeds the 72 character limit
"""

def function():
"""Short docstring"""
pass

class Example:
"""
Another long line in a class docstring that should be flagged by the linter tool
"""
pass
```

**Expected Output:**
```
File: test_docstring.py
Docstring lines exceeding 72 characters:
Line 2
Line 10
```

#### Test 2: Indentation Problems
Create `test_indentation.py`:
```python
def example():
if True:
print("indented")
print("dedented without blank line above") # Should be flagged

if False:
pass

print("properly separated") # Should NOT be flagged
```

**Expected Output:**
```
File: test_indentation.py
Lines with problematic indentation:
Line 4
```

#### Test 3: Block Statement Issues
Create `test_blocks.py`:
```python
x = 1
if x > 0: # Missing blank line before if
pass

def function():
pass
class TestClass: # Missing blank line before class
pass
```

**Expected Output:**
```
File: test_blocks.py
Block statements missing blank lines above:
Line 2
Line 6
```

#### Test 4: Mixed Issues
Create `test_mixed.py`:
```python
"""
This docstring has a line that is way too long and exceeds the character limit
"""

def problematic_function():
"""Another very long docstring line that should definitely be caught by the linter"""
x = 1
if x:
y = 2
z = 3 # Problematic dedentation
```

**Expected Output:**
```
File: test_mixed.py
Docstring lines exceeding 72 characters:
Line 2
Line 6
Lines with problematic indentation:
Line 10
Block statements missing blank lines above:
Line 8
```

#### Test 5: Keyword Statement Separation
Create `test_keywords.py`:
```python
a = 10
b = 9
c = 8
assert b == 9 # Missing blank line before assert
x = 1
if x > 0: # Missing blank line before if
pass
```

**Expected Output:**
```
File: test_keywords.py
Keyword statements missing blank lines from non-keyword statements:
Line 4
Line 6
```

### Automated Testing

Lintomatic includes a comprehensive test suite with both unit tests and property-based tests using Haskell's HUnit, QuickCheck, and Tasty frameworks.

#### Running the Test Suite

**Quick validation test:**
```bash
./test/validate_lintomatic.sh
```

**Comprehensive test suite:**
```bash
cabal test
```

**Using Make targets:**
```bash
make test # Quick functionality test
make test-cabal # Comprehensive test suite with cabal
make test-all # All tests (comprehensive + validation)
make test-comprehensive # Complete test suite via script
```

**Using the test script:**
```bash
./run_tests.sh
```

#### Test Suite Components

**Unit Tests:**
- **Utility Functions**: Tests for string manipulation functions (`strip`, `lstrip`, `rstrip`)
- **File Discovery**: Tests for Python file discovery in directory trees
- **Docstring Length**: Tests for detecting overly long docstring lines
- **Indentation**: Tests for problematic dedentation detection
- **Block Statements**: Tests for block statement formatting rules
- **Keyword Statements**: Tests for keyword/non-keyword transitions

**Property-Based Tests:**
- **String processing properties**: Idempotency, composition, whitespace handling
- **Edge case generation**: Automatic testing with randomly generated inputs
- **Invariant checking**: Ensures functions maintain expected mathematical properties

#### Test Statistics
The test suite includes:
- **31 test cases** covering all major functionality
- **100 property-based tests** per property (automatically generated)
- **Unit tests** for specific behavior validation
- **Integration tests** via the existing validation script

#### Coverage
Tests cover:
- ✅ Core linting functions
- ✅ File system operations
- ✅ String processing utilities
- ✅ Edge cases and error conditions
- ✅ Property-based invariants
- ✅ Backward compatibility

## Haskell Environment Checks

### Pre-compilation Checks
Verify your Haskell environment before building:

```bash
# Check GHC installation
ghc --version

# Check if required modules are available
ghc-pkg list | grep -E "(directory|filepath|base)"

# Test basic compilation
echo 'main = putStrLn "Hello"' > test.hs
ghc test.hs -o test
./test
rm test test.hi test.o test.hs
```

### Common Issues and Solutions

#### Issue: "Module not found" errors
**Solution:** Ensure GHC base libraries are installed:
```bash
cabal update
cabal install --dependencies-only .
```

#### Issue: Permission denied when running executable
**Solution:** Make the binary executable:
```bash
chmod +x lintomatic
```

#### Issue: "ghc: command not found"
**Solution:** Add GHC to your PATH or use full paths:
```bash
export PATH="$HOME/.ghcup/bin:$PATH"
# or
/usr/local/bin/ghc --make src/lintomatic.hs -o lintomatic
```

## Use Cases

### 1. Pre-commit Hook
Integrate lintomatic into your git workflow:
```bash
# In .git/hooks/pre-commit
#!/bin/bash
cd "$(git rev-parse --show-toplevel)"
if [ -x "./lintomatic" ]; then
./lintomatic
if [ $? -ne 0 ]; then
echo "Linting issues found. Commit aborted."
exit 1
fi
fi
```

### 2. CI/CD Pipeline
Add to your GitHub Actions workflow:
```yaml
- name: Install Haskell
uses: haskell/actions/setup@v2
with:
ghc-version: '9.2'

- name: Build lintomatic
run: ghc --make src/lintomatic.hs -o lintomatic

- name: Run Python linting
run: ./lintomatic
```

### 3. Development Workflow
- Run before committing Python code changes
- Integrate with IDE/editor as an external tool
- Use in code review processes to maintain consistency

### 4. Documentation Quality Assurance
- Ensure docstrings remain readable within line limits
- Maintain consistent Python code style across teams
- Automated enforcement of documentation standards

### 5. Legacy Code Cleanup
- Identify areas of existing codebases that need attention
- Gradual improvement of code quality
- Generate reports for technical debt assessment

## Future Features

### Planned Enhancements
- [ ] **Configurable Line Length**: Command-line option to set custom line limits
- [ ] **Configuration Files**: Support for `.lintomatic.yaml` configuration
- [ ] **Additional Python Checks**:
- Import statement organization
- Function argument formatting
- Comment line length validation
- [ ] **Output Formats**: JSON, XML, and CSV output options
- [ ] **IDE Integration**: LSP (Language Server Protocol) support
- [ ] **Performance Optimization**: Parallel file processing
- [ ] **Ignore Patterns**: `.lintomaticignore` file support
- [ ] **Fix Suggestions**: Automatic fixing capabilities for simple issues

### Possible Extensions
- [ ] **Multi-language Support**: Extend to other languages beyond Python
- [ ] **Custom Rule Engine**: Plugin system for user-defined rules
- [ ] **Git Integration**: Only check changed files in commits
- [ ] **Team Collaboration**: Shared configuration and team-specific rules
- [ ] **Metrics Dashboard**: Web interface for project linting statistics

### Contributing to Future Features
We welcome contributions! Areas where help is particularly needed:
- Performance optimization for large codebases
- Cross-platform testing and compatibility
- Additional linting rules based on Python PEP standards
- Integration with popular Python development tools

## Contributing

### Development Setup
1. Fork the repository
2. Clone your fork: `git clone https://github.com/yourusername/lintomatic.git`
3. Create a feature branch: `git checkout -b feature-name`
4. Make changes and test thoroughly
5. Submit a pull request

### Code Style
- Follow Haskell conventions and existing code style
- Add Haddock documentation for new functions
- Include test cases for new features
- Ensure compilation without warnings

### Reporting Issues
- Use GitHub Issues for bug reports and feature requests
- Include sample Python files that demonstrate the issue
- Specify your Haskell/GHC version and operating system

## License

MIT License - see [LICENSE](LICENSE) file for details.

## Acknowledgments

- Built with the Glasgow Haskell Compiler
- Inspired by Python PEP 8 and documentation best practices
- Thanks to the Haskell community for excellent tooling and libraries