Skip to content

feat: Add Pythonic code checker tool #42

@nnennandukwe

Description

@nnennandukwe

Summary

Add a new pythonic_check tool that detects non-idiomatic Python patterns and suggests Pythonic alternatives. This validates the shared core architecture and expands the code quality suite.

Parent Epic

Part of: Evolve into Python Code Quality MCP

Depends On

  • Refactor shared Astroid utilities into core module

Patterns to Detect

Loop Anti-patterns

Anti-pattern Pythonic Alternative
for i in range(len(items)): for i, item in enumerate(items):
for key in d.keys(): for key in d:
for i in range(len(a)): ... a[i] ... b[i] for x, y in zip(a, b):

Comparison Anti-patterns

Anti-pattern Pythonic Alternative
if x == True: / if x == False: if x: / if not x:
if x == None: if x is None:
type(x) == SomeClass isinstance(x, SomeClass)
if len(items) == 0: if not items:

Resource Management

Anti-pattern Pythonic Alternative
f = open(); ...; f.close() with open() as f:
Manual lock acquire/release with lock:

Collection Building

Anti-pattern Pythonic Alternative
l = []; for x in y: l.append(f(x)) [f(x) for x in y]
d = {}; for x in y: d[k] = v {k: v for x in y}
Loop with string concatenation "".join(...)

Mutable Defaults

Anti-pattern Pythonic Alternative
def foo(items=[]): def foo(items=None): items = items or []
def foo(d={}): def foo(d=None): d = d or {}

Other

Anti-pattern Pythonic Alternative
if x: return True else: return False return x / return bool(x)
Manual __enter__/__exit__ in simple cases @contextmanager
lambda x: func(x) Just func

MCP Tool Interface

{
  "name": "pythonic_check",
  "description": "Analyze Python code for non-idiomatic patterns and suggest Pythonic alternatives",
  "inputSchema": {
    "type": "object",
    "properties": {
      "file_path": {"type": "string"},
      "source_code": {"type": "string"}
    }
  }
}

Example Output

{
  "issues": [
    {
      "tool": "pythonic",
      "category": "non_idiomatic_loop",
      "severity": "warning",
      "message": "Use enumerate() instead of range(len())",
      "line": 42,
      "column": 4,
      "suggestion": "for i, item in enumerate(items):",
      "code_snippet": "for i in range(len(items)):"
    }
  ],
  "summary": {
    "total_issues": 5,
    "by_category": {
      "non_idiomatic_loop": 2,
      "mutable_default": 1,
      "comparison_to_none": 2
    }
  }
}

Implementation

  1. Create src/workshop_mcp/tools/pythonic_check/
  2. Define patterns in patterns.py
  3. Implement checker using core Astroid utilities
  4. Register tool in MCP server
  5. Add tests in tests/test_pythonic_checker.py

Acceptance Criteria

  • Detects at least 10 distinct anti-patterns
  • Uses shared core utilities (not duplicated code)
  • Provides actionable suggestions for each issue
  • Comprehensive test coverage
  • Registered as MCP tool

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions