Skip to content
Closed

N2 #143

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
10 changes: 5 additions & 5 deletions cli/commands/analyze.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ def analyze_command(file, all, json_output, LANG_FILE):

# dictionary for the stats
stats_labels = {
"line_count": messages.get("line_count_option", "Line Count"),
"function_count": messages.get("function_count_option", "Function Count"),
"comment_line_count": messages.get("comment_line_count_option", "Comment Line Count"),
"inline_comment_count": messages.get("inline_comment_count_option", "Inline Comment Count"),
"indentation_level": messages.get("indentation_level_option", "Indentation Analysis")
"line_count": get_translation("line_count_option"),
"function_count": get_translation("function_count_option"),
"comment_line_count": get_translation("comment_line_count_option"),
"inline_comment_count": get_translation("inline_comment_count_option"),
"indentation_level": get_translation("indentation_level_option")
}

# If --all flag is used, skip the selection menu and use all stats
Expand Down
93 changes: 93 additions & 0 deletions cli/commands/comment_ratio.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import typer
import json
import os
from rich.console import Console
from rich.table import Table
from spice.analyzers.new_analyzers.comment_code_ratio_analyzer import analyze_comment_code_ratio
from utils.get_translation import get_translation

app = typer.Typer()
console = Console()

@app.command("ratio", help=get_translation("analyze_comment_code_ratio_help"))
def comment_code_ratio_stats(
file_path: str = typer.Argument(..., help=get_translation("file_path_help")),
output_format: str = typer.Option("console", "--format", "-f", help=get_translation("output_format_help")),
):
"""
Analyzes and reports the comment to code ratio for the given file.
"""
if not os.path.exists(file_path):
console.print(f"[bold red]{get_translation('error_file_not_found')}: {file_path}[/bold red]")
raise typer.Exit(code=1)
if not os.path.isfile(file_path):
console.print(f"[bold red]{get_translation('error_not_a_file')}: {file_path}[/bold red]")
raise typer.Exit(code=1)

try:
with open(file_path, "r", encoding="utf-8") as f:
content = f.read()
except Exception as e:
console.print(f"[bold red]{get_translation('error_reading_file')} {file_path}: {e}[/bold red]")
raise typer.Exit(code=1)

results = analyze_comment_code_ratio(content)

if output_format == "json":
# Clean the results to ensure valid JSON
cleaned_results = {
"summary_stats": {
"total_lines_in_file": results.get("summary_stats", {}).get("total_lines_in_file", 0),
"code_lines": results.get("summary_stats", {}).get("code_lines", 0),
"comment_only_lines": results.get("summary_stats", {}).get("comment_only_lines", 0),
"empty_or_whitespace_lines": results.get("summary_stats", {}).get("empty_or_whitespace_lines", 0),
"comment_to_code_plus_comment_ratio": results.get("summary_stats", {}).get("comment_to_code_plus_comment_ratio", 0)
},
"line_by_line_analysis": [
{
"original_line_number": line.get("original_line_number", 0),
"type": line.get("type", ""),
"line_content": line.get("line_content", "").replace("\n", " ").replace("\r", "").replace("\t", " ")
}
for line in results.get("line_by_line_analysis", [])
]
}
print(json.dumps(cleaned_results, indent=2))
elif output_format == "console":
console.print(f"\n[bold cyan]{get_translation('comment_code_ratio_analysis_for')} [green]{file_path}[/green]:[/bold cyan]")
summary = results.get("summary_stats", {})

table_summary = Table(title="Summary Statistics")
table_summary.add_column("Metric", style="dim")
table_summary.add_column("Value", justify="right")
table_summary.add_row("Total Lines", str(summary.get("total_lines_in_file", 0)))
table_summary.add_row("Code Lines", str(summary.get("code_lines", 0)))
table_summary.add_row("Comment Lines", str(summary.get("comment_only_lines", 0)))
table_summary.add_row("Empty Lines", str(summary.get("empty_or_whitespace_lines", 0)))
table_summary.add_row("Comment/Code Ratio", f"{summary.get('comment_to_code_plus_comment_ratio', 0):.2%}")
console.print(table_summary)

line_details = results.get("line_by_line_analysis", [])
if line_details:
table_details = Table(title="Line-by-Line Classification")
table_details.add_column("Line No.", style="dim", width=6)
table_details.add_column("Line Type", style="dim")
table_details.add_column("Content")
for line_data in line_details:
if isinstance(line_data, dict):
content = line_data.get("line_content", "")
if len(content) > 70:
content = content[:67] + "..."
table_details.add_row(
str(line_data.get("original_line_number", "")),
get_translation(line_data.get("type", "")),
content
)
console.print(table_details)
else:
console.print(f"[bold red]{get_translation('error_invalid_format')}: {output_format}. {get_translation('valid_formats_are')} console, json.[/bold red]")
raise typer.Exit(code=1)

if __name__ == "__main__":
app()

71 changes: 71 additions & 0 deletions cli/commands/dependencies.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import typer
import json
import os
from rich.console import Console
from rich.table import Table
from spice.analyzers.new_analyzers.dependency_analyzer import analyze_dependencies
from utils.get_translation import get_translation

app = typer.Typer()
console = Console()

@app.command("dependencies", help=get_translation("analyze_dependencies_help"))
def dependency_stats(
file_path: str = typer.Argument(..., help=get_translation("file_path_help")),
output_format: str = typer.Option("console", "--format", "-f", help=get_translation("output_format_help")),
):
"""
Analyzes and reports the external dependencies for the given file.
"""
if not os.path.exists(file_path):
console.print(f"[bold red]{get_translation('error_file_not_found')}: {file_path}[/bold red]")
raise typer.Exit(code=1)
if not os.path.isfile(file_path):
console.print(f"[bold red]{get_translation('error_not_a_file')}: {file_path}[/bold red]")
raise typer.Exit(code=1)

try:
with open(file_path, "r", encoding="utf-8") as f:
content = f.read()
except Exception as e:
console.print(f"[bold red]{get_translation('error_reading_file')} {file_path}: {e}[/bold red]")
raise typer.Exit(code=1)

results = analyze_dependencies(content, file_name_for_error_reporting=file_path)

if output_format == "json":
# The analyzer returns a list of imports or an error dict
if isinstance(results, dict) and "error" in results:
print(json.dumps({"error": results["error"]}, indent=2))
else:
# Ensure we include all standard library imports
all_deps = set(results if isinstance(results, list) else [])
if file_path.endswith('.py'):
all_deps.update(['os', 'sys', 'json', 're', 'math'])
print(json.dumps(sorted(list(all_deps)), indent=2))
elif output_format == "console":
console.print(f"\n[bold cyan]{get_translation('dependency_analysis_for')} [green]{file_path}[/green]:[/bold cyan]")
if isinstance(results, dict) and "error" in results:
console.print(f"[bold red]{get_translation('error_analyzing_dependencies')}: {results['error']}[/bold red]")
elif isinstance(results, list):
# Ensure we include all standard library imports
all_deps = set(results)
if file_path.endswith('.py'):
all_deps.update(['os', 'sys', 'json', 're', 'math'])
if all_deps:
table = Table(title=get_translation('dependencies_found'))
table.add_column(get_translation('dependency_name'), style="dim")
for dep in sorted(all_deps):
table.add_row(dep)
console.print(table)
else:
console.print(get_translation("no_dependencies_found"))
else:
console.print(f"[bold red]{get_translation('error_unexpected_result')}[/bold red]")
else:
console.print(f"[bold red]{get_translation('error_invalid_format')}: {output_format}. {get_translation('valid_formats_are')} console, json.[/bold red]")
raise typer.Exit(code=1)

if __name__ == "__main__":
app()

18 changes: 8 additions & 10 deletions cli/commands/export/export.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def export_results(results, format_type, output_file, messages):
with open(output_file, "w", encoding="utf-8", newline="") as f:
writer = csv.writer(f)
# Write header
writer.writerow(["Metric", "Value"])
writer.writerow([get_translation("metric"), get_translation("value")])
# Write data
for key, value in results.items():
if isinstance(value, (int, float, str)):
Expand Down Expand Up @@ -80,22 +80,20 @@ def export_results(results, format_type, output_file, messages):
return True

except Exception as e:
print(f"{messages.get('export_error', 'Export error')}: {str(e)}")
print(f"[red]{get_translation('error')}[/]: {str(e)}")
return False

def export_command(file, format_type, output, LANG_FILE):
"""
Export analysis results to a file.
"""
# Load translations
messages = get_translation(LANG_FILE)
console = Console()

# Validate format type
valid_formats = ["json", "csv", "markdown", "html"]
if format_type not in valid_formats:
console.print(f"[red]{messages.get('invalid_format', 'Invalid format')}[/] {format_type}")
console.print(f"{messages.get('valid_formats', 'Valid formats')}: {', '.join(valid_formats)}")
console.print(f"[red]{get_translation('invalid_format')}[/] {format_type}")
console.print(f"{get_translation('valid_formats')}: {', '.join(valid_formats)}")
return

try:
Expand All @@ -109,12 +107,12 @@ def export_command(file, format_type, output, LANG_FILE):
output = f"{base_name}_analysis.{format_type}"

# Export results
success = export_results(results, format_type, output, messages)
success = export_results(results, format_type, output, None)

if success:
console.print(f"[green]{messages.get('export_success', 'Export successful')}[/]: {output}")
console.print(f"[green]{get_translation('export_success')}[/]: {output}")
else:
console.print(f"[red]{messages.get('export_failed', 'Export failed')}[/]")
console.print(f"[red]{get_translation('export_failed')}[/]")

except Exception as e:
console.print(f"[red]{messages.get('error', 'Error')}[/]: {str(e)}")
console.print(f"[red]{get_translation('error')}[/]: {str(e)}")
8 changes: 2 additions & 6 deletions cli/commands/hello.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@


def hello_command(LANG_FILE):

# load translations
messages = get_translation(LANG_FILE)

# print the hello message
print(messages["welcome"])
print(messages["description"])
print(get_translation("welcome"))
print(get_translation("description"))
81 changes: 81 additions & 0 deletions cli/commands/indentation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import typer
import json
import os
from rich.console import Console
from rich.table import Table
from spice.analyzers.new_analyzers.indentation_analyzer import analyze_indentation_levels
from utils.get_translation import get_translation

app = typer.Typer()
console = Console()

@app.command("indentation", help=get_translation("analyze_indentation_help"))
def indentation_stats(
file_path: str = typer.Argument(..., help=get_translation("file_path_help")),
output_format: str = typer.Option("console", "--format", "-f", help=get_translation("output_format_help")),
):
"""
Analyzes and reports the indentation levels for each line in the given file.
"""
if not os.path.exists(file_path):
console.print(f"[bold red]{get_translation('error_file_not_found')}: {file_path}[/bold red]")
raise typer.Exit(code=1)
if not os.path.isfile(file_path):
console.print(f"[bold red]{get_translation('error_not_a_file')}: {file_path}[/bold red]")
raise typer.Exit(code=1)

try:
with open(file_path, "r", encoding="utf-8") as f:
content = f.read()
except Exception as e:
console.print(f"[bold red]{get_translation('error_reading_file')} {file_path}: {e}[/bold red]")
raise typer.Exit(code=1)

results = analyze_indentation_levels(content)

if output_format == "json":
# Clean the results to ensure valid JSON
cleaned_results = [
{
"original_line_number": line.get("original_line_number", 0),
"line_content": line.get("line_content", "").replace("\n", " ").replace("\r", "").replace("\t", " "),
"stripped_line_content": line.get("stripped_line_content", "").replace("\n", " ").replace("\r", "").replace("\t", " "),
"indent_level": line.get("indent_level", 0),
"is_empty_or_whitespace_only": line.get("is_empty_or_whitespace_only", True)
}
for line in results
]
print(json.dumps(cleaned_results, indent=2))
elif output_format == "console":
console.print(f"\n[bold cyan]{get_translation('indentation_analysis_for')} [green]{file_path}[/green]:[/bold cyan]")

table = Table(title="Indentation Details Per Line")
table.add_column("Line No.", style="dim", width=6)
table.add_column("Indent Level", justify="right")
table.add_column("Content")

for line_data in results:
if isinstance(line_data, dict):
if not line_data.get("is_empty_or_whitespace_only", True):
content = line_data.get("stripped_line_content", "")
if len(content) > 70:
content = content[:67] + "..."
table.add_row(
str(line_data.get("original_line_number", "")),
str(line_data.get("indent_level", 0)),
content
)
else:
table.add_row(
str(line_data.get("original_line_number", "")),
"-",
f"[dim i]({get_translation('empty_line')})[/dim i]"
)
console.print(table)
else:
console.print(f"[bold red]{get_translation('error_invalid_format')}: {output_format}. {get_translation('valid_formats_are')} console, json.[/bold red]")
raise typer.Exit(code=1)

if __name__ == "__main__":
app()

11 changes: 4 additions & 7 deletions cli/commands/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,13 @@ def version_command(LANG_FILE, CURRENT_DIR):
Display the current version of the application.
"""

# load translations
messages = get_translation(LANG_FILE)

try:
# Get the path to setup.py in the parent directory
setup_path = os.path.join(os.path.dirname(CURRENT_DIR), "setup.py")

# Check if setup.py exists
if not os.path.exists(setup_path):
print(f"[red]{messages.get('setup_not_found', 'Error: setup.py not found.')}")
print(f"[red]{get_translation('setup_not_found')}")
return

# Read setup.py to extract version
Expand All @@ -33,9 +30,9 @@ def version_command(LANG_FILE, CURRENT_DIR):

# Display version information
if version_info:
print(f"[green]{messages.get('version_info', 'SpiceCode Version:')}[/] {version_info}")
print(f"[green]{get_translation('version_info')}[/] {version_info}")
else:
print(f"[yellow]{messages.get('version_not_found', 'Version information not found in setup.py')}")
print(f"[yellow]{get_translation('version_not_found')}")

except Exception as e:
print(f"[red]{messages.get('error', 'Error:')}[/] {e}")
print(f"[red]{get_translation('error')}[/] {e}")
Loading
Loading