Code Validation
Learn how DSPy Code validates your code for quality, correctness, and best practices.
What is Validation?
DSPy Code's validation engine checks your DSPy code for:
- â Correct DSPy patterns
- â Best practices
- â Syntax errors
- â Type hints
- â Documentation
- â Anti-patterns
Result: High-quality, production-ready DSPy code!
Quick Start
Validate Generated Code
After generating code:
Validate Existing File
Validate All Project Files
Validation Checks
1. Signature Validation
Checks:
- â
Inherits from
dspy.Signature - â
Has at least one
InputField - â
Has at least one
OutputField - â Fields have descriptions
- â Docstring present
- â Type hints used
Example - Valid Signature:
class SentimentSignature(dspy.Signature):
"""Analyze sentiment of text."""
text: str = dspy.InputField(
desc="Text to analyze"
)
sentiment: str = dspy.OutputField(
desc="positive, negative, or neutral"
)
Example - Invalid Signature:
# â Missing docstring
# â No field descriptions
# â No type hints
class SentimentSignature(dspy.Signature):
text = dspy.InputField()
sentiment = dspy.OutputField()
2. Module Validation
Checks:
- â
Inherits from
dspy.Module - â
Has
__init__method - â
Calls
super().__init__() - â
Has
forwardmethod - â Uses DSPy predictors
- â Returns proper values
Example - Valid Module:
class SentimentAnalyzer(dspy.Module):
def __init__(self):
super().__init__()
self.predictor = dspy.Predict(SentimentSignature)
def forward(self, text: str) -> dspy.Prediction:
return self.predictor(text=text)
Example - Invalid Module:
# â Doesn't inherit from dspy.Module
# â No super().__init__()
# â No forward method
class SentimentAnalyzer:
def __init__(self):
self.predictor = dspy.Predict(SentimentSignature)
def analyze(self, text): # â Should be 'forward'
return self.predictor(text=text)
3. Predictor Usage
Checks:
- â Uses valid DSPy predictors
- â Predictor initialized correctly
- â Signature passed to predictor
- â Predictor called properly
Valid predictors:
dspy.Predictdspy.ChainOfThoughtdspy.ReActdspy.ProgramOfThoughtdspy.MultiChainComparison
Example - Valid:
Example - Invalid:
# â Not a DSPy predictor
self.predictor = SentimentSignature()
# â Wrong usage
result = self.predictor.predict(text=input_text)
4. Best Practices
Checks:
- â Descriptive variable names
- â Proper error handling
- â No hardcoded values
- â Modular design
- â DRY principle
- â Clear logic flow
Example - Good Practices:
class EmailClassifier(dspy.Module):
"""Classify emails into categories."""
def __init__(self, categories: List[str]):
super().__init__()
# Validate input
if not categories:
raise ValueError("Categories list cannot be empty")
self.categories = categories
self.classifier = dspy.ChainOfThought(EmailSignature)
def forward(self, email: str) -> dspy.Prediction:
"""Classify an email."""
# Input validation
if not email or not email.strip():
raise ValueError("Email cannot be empty")
# Classify
try:
result = self.classifier(
email=email,
categories=", ".join(self.categories)
)
return result
except Exception as e:
logger.error(f"Classification failed: {e}")
raise
Example - Bad Practices:
class EmailClassifier(dspy.Module):
def __init__(self):
super().__init__()
# â Hardcoded categories
self.c = dspy.ChainOfThought(EmailSignature)
def forward(self, e): # â Unclear parameter name
# â No error handling
# â No validation
r = self.c(email=e, categories="spam,work,personal")
return r
5. Type Hints
Checks:
- â Function parameters have types
- â Return types specified
- â Field types in signatures
- â Consistent type usage
Example - Good Type Hints:
from typing import List, Optional
import dspy
class Analyzer(dspy.Module):
def __init__(self, model_name: str = "gpt-5-nano"):
super().__init__()
self.model_name: str = model_name
self.predictor: dspy.Predict = dspy.Predict(AnalysisSignature)
def forward(
self,
text: str,
context: Optional[str] = None
) -> dspy.Prediction:
return self.predictor(text=text, context=context or "")
Example - Missing Type Hints:
class Analyzer(dspy.Module):
def __init__(self, model_name="gpt-5-nano"): # â No type
super().__init__()
self.model_name = model_name
self.predictor = dspy.Predict(AnalysisSignature)
def forward(self, text, context=None): # â No types
return self.predictor(text=text, context=context or "")
6. Documentation
Checks:
- â Module docstring
- â Method docstrings
- â Signature docstring
- â Parameter descriptions
- â Return value descriptions
Example - Well Documented:
class SentimentAnalyzer(dspy.Module):
"""
Analyze sentiment of text using DSPy.
This module uses ChainOfThought reasoning to classify
text sentiment as positive, negative, or neutral.
Attributes:
predictor: DSPy ChainOfThought predictor
"""
def __init__(self):
"""Initialize the sentiment analyzer."""
super().__init__()
self.predictor = dspy.ChainOfThought(SentimentSignature)
def forward(self, text: str) -> dspy.Prediction:
"""
Analyze sentiment of given text.
Args:
text: Text to analyze
Returns:
Prediction with sentiment field
Raises:
ValueError: If text is empty
"""
if not text:
raise ValueError("Text cannot be empty")
return self.predictor(text=text)
Validation Report
Report Structure
ââââââââââââââââââââââââ Validation Report ââââââââââââââââââââââââŽ
â â
â File: sentiment_analyzer.py â
â â
â â Signature Structure â
â - Inherits from dspy.Signature â
â - Has InputField and OutputField â
â - Fields have descriptions â
â â
â â Module Structure â
â - Inherits from dspy.Module â
â - Has __init__ and forward methods â
â - Uses DSPy predictors â
â â
â â Best Practices â
â â Descriptive names â
â â Error handling â
â â Missing type hints on line 15 â
â â
â â Documentation â
â - Module docstring present â
â - Method docstrings present â
â â
â Quality Score: 92/100 â
â â
â Issues Found: 1 â
â Warnings: 1 â
â â
â°âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ¯
Recommendations:
âĸ Add type hint to parameter 'text' on line 15
Score Breakdown
100 points total:
- Signature structure: 20 points
- Module structure: 20 points
- Best practices: 30 points
- Documentation: 15 points
- Type hints: 15 points
Score ranges:
- 90-100: Excellent âââ
- 80-89: Good ââ
- 70-79: Acceptable â
- <70: Needs improvement â ī¸
Anti-Pattern Detection
Common Anti-Patterns
1. Direct LLM Calls:
# â Anti-pattern
import openai
response = openai.ChatCompletion.create(...)
# â Use DSPy
predictor = dspy.Predict(MySignature)
response = predictor(input=data)
2. String-Based Prompts:
# â Anti-pattern
prompt = f"Analyze this: {text}"
response = llm(prompt)
# â Use Signatures
class AnalysisSignature(dspy.Signature):
text = dspy.InputField()
analysis = dspy.OutputField()
predictor = dspy.Predict(AnalysisSignature)
response = predictor(text=text)
3. Manual Prompt Engineering:
# â Anti-pattern
prompt = "You are an expert. Analyze carefully. Think step by step..."
# â Use ChainOfThought
predictor = dspy.ChainOfThought(AnalysisSignature)
4. Hardcoded Examples:
# â Anti-pattern
prompt = """
Example 1: ...
Example 2: ...
Now analyze: {text}
"""
# â Use DSPy optimization
optimized = optimizer.compile(program, trainset=examples)
5. No Error Handling:
# â Anti-pattern
def forward(self, text):
return self.predictor(text=text)
# â Add error handling
def forward(self, text: str) -> dspy.Prediction:
if not text:
raise ValueError("Text cannot be empty")
try:
return self.predictor(text=text)
except Exception as e:
logger.error(f"Prediction failed: {e}")
raise
Auto-Fix Suggestions
Fixable Issues
DSPy Code can suggest fixes for common issues:
Missing Type Hints:
Issue: Missing type hint on parameter 'text'
Suggested fix:
def forward(self, text: str) -> dspy.Prediction:
Missing Docstring:
Issue: Module missing docstring
Suggested fix:
class MyModule(dspy.Module):
"""[Description of what this module does]"""
Missing Field Description:
Apply Fixes
DSPy Code applies suggested fixes automatically!
Validation in Workflow
During Development
Validate frequently:
â Create a classifier
[Code generated]
â /validate
â Score: 95/100
â Add confidence scores
[Code updated]
â /validate
â Score: 88/100 - Missing type hint
â Fix the type hint issue
[Code fixed]
â /validate
â Score: 98/100
Before Saving
Always validate before saving:
Before Optimization
Ensure code quality before GEPA:
In CI/CD
Integrate validation in CI:
Custom Validation Rules
Add Project-Specific Rules
Create .dspy-code/validation-rules.yaml:
rules:
# Require specific predictor types
required_predictors:
- ChainOfThought
- ReAct
# Disallow certain patterns
disallowed_patterns:
- "import openai"
- "import anthropic"
# Require specific fields
required_signature_fields:
- description
- examples
# Naming conventions
naming:
signature_suffix: "Signature"
module_suffix: "Module"
# Minimum quality score
min_quality_score: 85
Enable Custom Rules
Validation API
Programmatic Validation
Use validation in your scripts:
from dspy_code.validation import ModuleValidator
# Create validator
validator = ModuleValidator()
# Validate file
report = validator.validate_file("my_module.py")
# Check results
if report.score >= 90:
print("Excellent code!")
elif report.score >= 70:
print("Good code, minor issues")
else:
print("Needs improvement")
# Get issues
for issue in report.issues:
print(f"{issue.severity}: {issue.message} (line {issue.line})")
# Get suggestions
for suggestion in report.suggestions:
print(f"Suggestion: {suggestion}")
Batch Validation
Validate multiple files:
from dspy_code.validation import ProjectValidator
validator = ProjectValidator()
reports = validator.validate_project("./generated")
for filepath, report in reports.items():
print(f"{filepath}: {report.score}/100")
Best Practices
1. Validate Early and Often
Don't wait until the end:
2. Aim for 90+
Strive for excellent scores:
- 90-100: Production-ready
- 80-89: Good for prototypes
- <80: Needs work
3. Fix Issues Incrementally
Don't try to fix everything at once:
4. Use Auto-Fix
Let DSPy Code help:
5. Learn from Reports
Understand why issues occur:
â Why is this an issue?
â How can I avoid this in the future?
â What's the best practice here?
Troubleshooting
False Positives
If validator flags valid code:
Custom Patterns
If your code uses custom patterns:
Performance Issues
For large files:
Summary
Validation ensures:
- â Correct DSPy patterns
- â Best practices followed
- â High code quality
- â Production readiness
- â Maintainability
Key points:
- Validate frequently
- Aim for 90+ scores
- Fix issues incrementally
- Use auto-fix when available
- Learn from validation reports