This guide demonstrates how to determine docs coverage and create documentation for your codebase.
This primarily leverages two APIs:
Determining Documentation Coverage
In order to determine the extent of your documentation coverage, you can iterate through all symbols of interest and count the number of docstrings:
To see your current documentation coverage, you can iterate through all symbols of interest and count the number of docstrings:
# Initialize counters
total_functions = 0
functions_with_docs = 0
total_classes = 0
classes_with_docs = 0
# Check functions
for function in codebase.functions:
total_functions += 1
if function.docstring:
functions_with_docs += 1
# Check classes
for cls in codebase.classes:
total_classes += 1
if cls.docstring:
classes_with_docs += 1
# Calculate percentages
func_coverage = (functions_with_docs / total_functions * 100) if total_functions > 0 else 0
class_coverage = (classes_with_docs / total_classes * 100) if total_classes > 0 else 0
# Print results with emojis
print("\n📊 Documentation Coverage Report:")
print(f"\n📝 Functions:")
print(f" • Total: {total_functions}")
print(f" • Documented: {functions_with_docs}")
print(f" • Coverage: {func_coverage:.1f}%")
print(f"\n📚 Classes:")
print(f" • Total: {total_classes}")
print(f" • Documented: {classes_with_docs}")
print(f" • Coverage: {class_coverage:.1f}%")
print(f"\n🎯 Overall Coverage: {((functions_with_docs + classes_with_docs) / (total_functions + total_classes) * 100):.1f}%")
Which provides the following output:
📊 Documentation Coverage Report:
📝 Functions:
• Total: 1384
• Documented: 331
• Coverage: 23.9%
📚 Classes:
• Total: 453
• Documented: 91
• Coverage: 20.1%
🎯 Overall Coverage: 23.0%
Identifying Areas of Low Documentation Coverage
To identify areas of low documentation coverage, you can iterate through all directories and count the number of functions with docstrings.
# Track directory stats
dir_stats = {}
# Analyze each directory
for directory in codebase.directories:
# Skip test, sql and alembic directories
if any(x in directory.path.lower() for x in ['test', 'sql', 'alembic']):
continue
# Get undecorated functions
funcs = [f for f in directory.functions if not f.is_decorated]
total = len(funcs)
# Only analyze dirs with >10 functions
if total > 10:
documented = sum(1 for f in funcs if f.docstring)
coverage = (documented / total * 100)
dir_stats[directory.path] = {
'total': total,
'documented': documented,
'coverage': coverage
}
# Find lowest coverage directory
if dir_stats:
lowest_dir = min(dir_stats.items(), key=lambda x: x[1]['coverage'])
path, stats = lowest_dir
print(f"📉 Lowest coverage directory: '{path}'")
print(f" • Total functions: {stats['total']}")
print(f" • Documented: {stats['documented']}")
print(f" • Coverage: {stats['coverage']:.1f}%")
# Print all directory stats for comparison
print("\n📊 All directory coverage rates:")
for path, stats in sorted(dir_stats.items(), key=lambda x: x[1]['coverage']):
print(f" '{path}': {stats['coverage']:.1f}% ({stats['documented']}/{stats['total']} functions)")
Which provides the following output:
📉 Lowest coverage directory: 'codegen-backend/app/utils/github_utils/branch'
• Total functions: 12
• Documented: 0
• Coverage: 0.0%
📊 All directory coverage rates:
'codegen-backend/app/utils/github_utils/branch': 0.0% (0/12 functions)
'codegen-backend/app/utils/slack': 14.3% (2/14 functions)
'codegen-backend/app/modal_app/github': 18.2% (2/11 functions)
'codegen-backend/app/modal_app/slack': 18.2% (2/11 functions)
'codegen-backend/app/utils/github_utils/webhook': 21.4% (6/28 functions)
'codegen-backend/app/modal_app/cron': 23.1% (3/13 functions)
'codegen-backend/app/utils/github_utils': 23.5% (39/166 functions)
'codegen-backend/app/codemod': 25.0% (7/28 functions)
Leveraging AI for Generating Documentation
For non-trivial codebases, it can be challenging to achieve full documentation coverage.
The most efficient way to edit informative docstrings is to use codebase.ai to generate docstrings, then use the set_docstring method to update the docstring.
Learn more about using AI in our
guides.
# Import datetime for timestamp
from datetime import datetime
# Get current timestamp
timestamp = datetime.now().strftime("%B %d, %Y")
print("📚 Generating and Updating Function Documentation")
# Process all functions in the codebase
for function in codebase.functions:
current_docstring = function.docstring()
if current_docstring:
# Update existing docstring to be more descriptive
new_docstring = codebase.ai(
f"Update the docstring for {function.name} to be more descriptive and comprehensive.",
target=function
)
new_docstring += f"\n\nUpdated on: {timestamp}"
else:
# Generate new docstring for function
new_docstring = codebase.ai(
f"Generate a comprehensive docstring for {function.name} including parameters, return type, and description.",
target=function
)
new_docstring += f"\n\nCreated on: {timestamp}"
# Set the new or updated docstring
function.set_docstring(new_docstring)
Adding Explicit Parameter Names and Types
Alternatively, you can also rely on deterministic string formatting to edit docstrings.
To add “Google-style” parameter names and types to a function docstring, you can use the following code snippet:
# Iterate through all functions in the codebase
for function in codebase.functions:
# Skip if function already has a docstring
if function.docstring:
continue
# Build parameter documentation
param_docs = []
for param in function.parameters:
param_type = param.type.source if param.is_typed else "Any"
param_docs.append(f" {param.name} ({param_type}): Description of {param.name}")
# Get return type if present
return_type = function.return_type.source if function.return_type else "None"
# Create Google-style docstring
docstring = f'''"""
Description of {function.name}.
Args:
{chr(10).join(param_docs)}
Returns:
{return_type}: Description of return value
"""'''
# Set the new docstring
function.set_docstring(docstring)