Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,18 @@ CodeGraphContext is already being explored by developers and projects for:

If you’re using CodeGraphContext in your project, feel free to open a PR and add it here! 🚀

##Examples of Natural Language Queries

- Index /my-project.

- Analyze callers of my_function.

- Show inheritance for BaseController.

- Find dead code.

- Trace dependencies of DatabaseManager module.

## Dependencies

- `neo4j>=5.15.0`
Expand Down
141 changes: 87 additions & 54 deletions src/codegraphcontext/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -1261,95 +1261,128 @@ def analyze_dependencies(
return
db_manager, graph_builder, code_finder = services

try:
results = code_finder.find_module_dependencies(target)

if not results.get('importers') and not results.get('imports'):
console.print(f"[yellow]No dependency information found for '{target}'[/yellow]")
return

if results.get('importers'):
console.print(f"\n[bold cyan]Files that import '{target}':[/bold cyan]")
table = Table(show_header=True, header_style="bold magenta", box=box.ROUNDED)
table.add_column("File", style="cyan", overflow="fold")
table.add_column("Line", style="green", justify="right")

for imp in results['importers']:
table.add_row(
imp.get('importer_file_path', ''),
str(imp.get('import_line_number', ''))
)

console.print(table)

if results.get('imports'):
console.print(f"\n[bold cyan]Modules imported by '{target}':[/bold cyan]")
table = Table(show_header=True, header_style="bold magenta", box=box.ROUNDED)
table.add_column("Module", style="cyan")
table.add_column("Alias", style="yellow")

for imp in results['imports']:
table.add_row(
imp.get('imported_module', ''),
imp.get('import_alias', '') or "-"
)

console.print(table)

finally:
db_manager.close_driver()

@analyze_app.command("deps")
def analyze_dependencies(
target: str = typer.Argument(..., help="Module name"),
show_external: bool = typer.Option(True, "--external/--no-external", help="Show external dependencies")
):
"""
Show dependencies and imports for a module.
"""
_load_credentials()
services = _initialize_services()
if not all(services):
return
db_manager, graph_builder, code_finder = services

try:
results = code_finder.find_module_dependencies(target)

if not results.get('importers') and not results.get('imports'):
console.print(f"[yellow]No dependency information found for '{target}'[/yellow]")
return

# Show who imports this module
if results.get('importers'):
console.print(f"\n[bold cyan]Files that import '{target}':[/bold cyan]")
table = Table(show_header=True, header_style="bold magenta", box=box.ROUNDED)
table.add_column("File", style="cyan", overflow="fold")
table.add_column("Line", style="green", justify="right")

for imp in results['importers']:
table.add_row(
imp.get('importer_file_path', ''),
str(imp.get('import_line_number', ''))
)

console.print(table)

# Show what this module imports

if results.get('imports'):
console.print(f"\n[bold cyan]Modules imported by '{target}':[/bold cyan]")
table = Table(show_header=True, header_style="bold magenta", box=box.ROUNDED)
table.add_column("Module", style="cyan")
table.add_column("Alias", style="yellow")

for imp in results['imports']:
table.add_row(
imp.get('imported_module', ''),
imp.get('import_alias', '') or "-"
)

console.print(table)

finally:
db_manager.close_driver()

@analyze_app.command("tree")
def analyze_inheritance_tree(
class_name: str = typer.Argument(..., help="Class name"),
file: Optional[str] = typer.Option(None, "--file", "-f", help="Specific file path")
):
"""
Show inheritance hierarchy for a class.

Example:
cgc analyze tree MyClass
cgc analyze tree MyClass --file src/models.py
"""
_load_credentials()
services = _initialize_services()
if not all(services):
return
db_manager, graph_builder, code_finder = services

try:
results = code_finder.find_class_hierarchy(class_name, file)

console.print(f"\n[bold cyan]Class Hierarchy for '{class_name}':[/bold cyan]\n")

# Show parent classes
if results.get('parent_classes'):
console.print("[bold yellow]Parents (inherits from):[/bold yellow]")
for parent in results['parent_classes']:
console.print(f" ⬆ [cyan]{parent.get('parent_class', '')}[/cyan] [dim]({parent.get('parent_file_path', '')}:{parent.get('parent_line_number', '')})[/dim]")
else:
console.print("[dim]No parent classes found[/dim]")

console.print()

# Show child classes
if results.get('child_classes'):
try:
# Show child classes
if results.get('child_classes'):
console.print("[bold yellow]Children (classes that inherit from this):[/bold yellow]")
for child in results['child_classes']:
console.print(f" ⬇ [cyan]{child.get('child_class', '')}[/cyan] [dim]({child.get('child_file_path', '')}:{child.get('child_line_number', '')})[/dim]")
else:
console.print("[dim]No child classes found[/dim]")

console.print()

# Show methods
if results.get('methods'):
console.print(f"[bold yellow]Methods ({len(results['methods'])}):[/bold yellow]")
for method in results['methods'][:10]: # Limit to 10
console.print(f" • [green]{method.get('method_name', '')}[/green]({method.get('method_args', '')})")
if len(results['methods']) > 10:
console.print(f" [dim]... and {len(results['methods']) - 10} more[/dim]")
console.print(
f" ⬇ [cyan]{child.get('child_class', '')}[/cyan] "
f"[dim]({child.get('child_file_path', '')}:{child.get('child_line_number', '')})[/dim]"
)
else:
console.print("[dim]No child classes found[/dim]")

console.print()

# Show methods
if results.get('methods'):
console.print(f"[bold yellow]Methods ({len(results['methods'])}):[/bold yellow]")
for method in results['methods'][:10]: # Limit to 10
console.print(
f" • [green]{method.get('method_name', '')}[/green]"
f"({method.get('method_args', '')})"
)

if len(results['methods']) > 10:
console.print(
f" [dim]... and {len(results['methods']) - 10} more[/dim]"
)

finally:
db_manager.close_driver()
db_manager.close_driver()


@analyze_app.command("complexity")
def analyze_complexity(
Expand Down