Back to list
jarosser06

python-basics

by jarosser06

Quality assurance for AI-augmented codebases - validates project structure and AI agent collaboration patterns through custom rules.

1🍴 0📅 Jan 6, 2026

SKILL.md


name: python-basics description: Expert in Python 3.10+ fundamentals and best practices for the Drift project including import ordering (isort), code organization, and PEP 8 conventions. Use when writing or reviewing Python code.

Python Basics Skill

Learn how to write clean, well-organized Python code following Drift project conventions.

How to Organize Imports

When writing Python files, place imports immediately after the module docstring and organize them in three groups:

"""Module for analyzing conversation logs."""

# Standard library imports
import json
import os
from pathlib import Path
from typing import Any, Optional

# Third-party imports
import boto3
import click
from botocore.exceptions import ClientError

# Local imports
from drift.core.parser import parse_conversation
from drift.core.detector import DriftDetector
from drift.utils.config import load_config

Within Each Group

Organize imports consistently:

  1. import x statements first
  2. from x import y statements second
  3. Alphabetically within each subgroup
# Good organization
import json
import os
from pathlib import Path
from typing import Any, Dict

# Poor organization (mixed order)
from typing import Any, Dict
import os
from pathlib import Path
import json

Why No Inline Imports?

Understanding the reasoning helps you make better architectural decisions:

  1. Readability: Dependencies should be visible at the top of the file
  2. Maintainability: Easier to track and manage dependencies
  3. Performance: Module loading happens once, not repeatedly
  4. Static Analysis: Tools can analyze dependencies properly
  5. PEP 8 Compliance: Follows Python style guide recommendations

The Exception: TYPE_CHECKING Blocks

When you need to avoid circular imports for type hints only:

from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from drift.core.detector import DriftDetector  # OK: Type checking only

def process(detector: "DriftDetector") -> None:
    """Process using detector."""
    pass

This technique allows forward references without runtime circular dependencies.

How to Fix Import Issues

When your linter flags import problems:

Using isort

# Auto-sort all imports
isort .

# Check what would change
isort --check-only .

# Sort a specific file
isort src/drift/core/parser.py

Manual Fixes

Problem: Imports mixed with code

# Before
import json

def process():
    pass

import os  # Wrong location!
# After
import json
import os

def process():
    pass

Problem: Wrong grouping

# Before
import json
import click  # Third-party mixed with stdlib
from drift.core import parser
# After
import json

import click

from drift.core import parser

How to Structure Python Modules

Follow this organization pattern:

"""Module for drift detection.

This module provides the core drift detection functionality.
"""

# Imports (organized as shown above)
import json
from typing import Any

from drift.core.parser import parse_conversation

# Constants
DEFAULT_MODEL = "anthropic.claude-v2"
MAX_RETRIES = 3

# Classes
class DriftDetector:
    """Detects drift patterns in conversations."""

    def __init__(self, model: str = DEFAULT_MODEL):
        """Initialize detector."""
        self.model = model

# Functions
def detect_drift(conversation: dict) -> list[str]:
    """Detect drift in conversation."""
    detector = DriftDetector()
    return detector.analyze(conversation)

# Main execution
if __name__ == "__main__":
    main()

How to Handle Circular Imports

When you encounter circular import errors, try these solutions in order:

1. Refactor to Remove the Circle (Preferred)

Move shared code to a separate module:

# Before: module_a.py imports module_b.py, module_b.py imports module_a.py

# After: Create module_c.py with shared code
# module_a.py imports module_c.py
# module_b.py imports module_c.py

2. Use Dependency Injection

Pass dependencies as function parameters instead of importing:

# Instead of importing DriftDetector in multiple places
def analyze_file(path: str, detector: DriftDetector) -> dict:
    """Analyze file using provided detector."""
    return detector.analyze(path)

3. Import at Function Level (Last Resort)

Only when the above solutions don't work:

def process_with_detector():
    """Process using detector."""
    from drift.core.detector import DriftDetector  # Local import
    detector = DriftDetector()
    return detector.analyze()

How to Add Type Hints

Use this pattern for function signatures:

from typing import Optional

def detect_drift(
    conversation: dict,
    drift_type: str,
    config: Optional[dict] = None
) -> list[str]:
    """Detect drift in conversation.

    -- conversation: Conversation data
    -- drift_type: Type of drift to detect
    -- config: Optional configuration

    Returns list of detected drift patterns.
    """
    pass

For optional parameters:

from typing import Optional

def fetch_user(user_id: str, cache: Optional[Cache] = None) -> User:
    """Fetch user by ID with optional caching."""
    if cache:
        return cache.get(user_id)
    return database.fetch(user_id)

How to Handle Errors Effectively

Be specific with exception types:

# Good - specific exceptions
try:
    data = json.load(f)
except json.JSONDecodeError as e:
    logger.error(f"Invalid JSON in {path}: {e}")
    raise ValueError(f"Cannot parse {path}") from e
except FileNotFoundError:
    logger.error(f"File not found: {path}")
    raise

# Avoid - too broad
try:
    data = json.load(f)
except Exception as e:  # Catches too much!
    raise

When to catch broad exceptions:

  • At application boundaries (CLI entry points)
  • When you need to clean up resources regardless of error type
  • When logging all errors for debugging

How to Format Strings

Use f-strings for readability and performance:

# Recommended
message = f"Found {count} drift instances in {file_path}"
details = f"Status: {status}, Time: {elapsed:.2f}s"

# Avoid (harder to read)
message = "Found {} drift instances in {}".format(count, file_path)
message = "Found " + str(count) + " drift instances"

How to Use Black for Formatting

# Format all files
black .

# Check what would change without modifying
black --check .

# Format specific file
black src/drift/core/parser.py

# See what would change
black --diff src/drift/core/parser.py

Code Review Workflow

When reviewing or writing Python code, work through these steps:

1. Check Imports

  • Are all imports at the top?
  • Are they grouped correctly (stdlib → third-party → local)?
  • Any inline imports that should be moved?
  • Any wildcard or unused imports?

2. Check Type Hints

  • Do public functions have type hints?
  • Are Optional types used correctly?

3. Check Naming

  • Functions/variables: snake_case?
  • Classes: PascalCase?
  • Constants: UPPER_CASE?
  • Private identifiers: _leading_underscore?

4. Check Formatting

  • Lines under 100 characters?
  • Proper spacing (2 lines between classes/functions, 1 line between methods)?
  • No trailing whitespace?

5. Run Auto-formatters

# Fix all formatting automatically
black .
isort .

# Verify
black --check .
isort --check-only .

Anti-Pattern Examples

Inline Imports

# Avoid this pattern
def process_data(data):
    import json  # Import should be at top
    return json.loads(data)

# Use this instead
import json

def process_data(data):
    return json.loads(data)

Wildcard Imports

# Avoid - unclear what's being imported
from drift.core import *

# Use explicit imports
from drift.core import DriftDetector, parse_conversation

Unused Imports

# Avoid - these imports aren't used
import json
import os
from typing import Any

def hello():
    print("hello")

# Keep it clean
def hello():
    print("hello")

Run isort and your linter will catch these automatically.

Common Patterns

Optional Configuration

from typing import Optional

def analyze(
    data: dict,
    config: Optional[dict] = None
) -> dict:
    """Analyze data with optional configuration."""
    if config is None:
        config = get_default_config()
    return _analyze_impl(data, config)

Path Handling

from pathlib import Path

def read_config(config_path: str | Path) -> dict:
    """Read configuration from file."""
    path = Path(config_path)
    if not path.exists():
        raise FileNotFoundError(f"Config not found: {path}")
    return json.loads(path.read_text())

Context Managers

def process_file(path: str) -> dict:
    """Process file with automatic cleanup."""
    with open(path) as f:
        data = json.load(f)
    # File automatically closed here
    return data

Score

Total Score

75/100

Based on repository quality metrics

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

+10
説明文

100文字以上の説明がある

+10
人気

GitHub Stars 100以上

0/15
最近の活動

3ヶ月以内に更新

+5
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

+5

Reviews

💬

Reviews coming soon