import os
import tempfile
import asyncio
from pathlib import Path
async def main():
print("Loregrep Python Package - Builder Pattern API Example")
print("=" * 55)
try:
import loregrep
print(f"โ
Successfully imported loregrep v{loregrep.__version__}")
except ImportError as e:
print(f"โ Failed to import loregrep: {e}")
print("Make sure to build the package with: maturin develop --features python")
return
print("\n1. Available AI Tools:")
tools = loregrep.LoreGrep.get_tool_definitions()
for i, tool in enumerate(tools, 1):
print(f" {i}. {tool.name}: {tool.description}")
print("\n2. Creating LoreGrep instance with enhanced API...")
print(" Option 1: Auto-discovery (zero configuration)")
try:
auto_loregrep = loregrep.LoreGrep.auto_discover(".")
print(" โ
Auto-discovery instance created successfully")
print(f" ๐ Detected project languages and configured analyzers")
except Exception as e:
print(f" โ ๏ธ Auto-discovery failed: {e}")
auto_loregrep = None
print("\n Option 2: Enhanced builder with convenience methods")
try:
enhanced_loregrep = (loregrep.LoreGrep.builder()
.with_rust_analyzer() .with_python_analyzer() .optimize_for_performance() .exclude_test_dirs() .build()) print(" โ
Enhanced builder instance created successfully")
except Exception as e:
print(f" โ ๏ธ Enhanced builder failed: {e}")
enhanced_loregrep = None
print("\n Option 3: Project-specific presets")
try:
preset_loregrep = loregrep.LoreGrep.polyglot_project(".") print(" โ
Polyglot project preset created successfully")
except Exception as e:
print(f" โ ๏ธ Project preset failed: {e}")
preset_loregrep = None
loregrep_instance = auto_loregrep or enhanced_loregrep or preset_loregrep
if not loregrep_instance:
print("โ Failed to create any LoreGrep instance")
return
print(f"\n ๐ Using instance: {loregrep_instance}")
print("\n3. Creating sample repository...")
temp_dir = create_sample_repository()
try:
print(f"\n4. Scanning repository at {temp_dir}...")
result = await loregrep_instance.scan(temp_dir)
print("โ
Repository scan completed!")
print(f" ๐ Files scanned: {result.files_scanned}")
print(f" ๐ง Functions found: {result.functions_found}")
print(f" ๐ฆ Structs found: {result.structs_found}")
print(f" โฑ๏ธ Duration: {result.duration_ms}ms")
if len(tools) > 0:
print(f"\n5. Demonstrating tool execution...")
try:
print(" ๐ Testing search_functions tool...")
func_result = await loregrep_instance.execute_tool("search_functions", {
"pattern": "Config",
"limit": 5
})
print(f" โ
search_functions executed successfully")
print(f" ๐ Functions found:")
print(f" {func_result.content}")
except Exception as e:
print(f" โ ๏ธ search_functions demo failed: {e}")
try:
print("\n ๐ Testing search_structs tool...")
struct_result = await loregrep_instance.execute_tool("search_structs", {
"pattern": "Config",
"limit": 5
})
print(f" โ
search_structs executed successfully")
print(f" ๐ฆ Structs found:")
print(f" {struct_result.content}")
except Exception as e:
print(f" โ ๏ธ search_structs demo failed: {e}")
try:
print("\n ๐ณ Testing get_repository_tree tool...")
tree_result = await loregrep_instance.execute_tool("get_repository_tree", {
"include_file_details": True,
"max_depth": 2
})
print(f" โ
get_repository_tree executed successfully")
print(f" ๐๏ธ Repository structure:")
print(f" {tree_result.content}")
except Exception as e:
print(f" โ ๏ธ get_repository_tree demo failed: {e}")
try:
rust_file_path = os.path.join(temp_dir, "config.rs")
if os.path.exists(rust_file_path):
print("\n ๐ Testing analyze_file tool...")
analyze_result = await loregrep_instance.execute_tool("analyze_file", {
"file_path": rust_file_path,
"include_source": False
})
print(f" โ
analyze_file executed successfully")
print(f" ๐ File analysis (config.rs):")
import json
try:
analysis_data = json.loads(analyze_result.content)
if "functions" in analysis_data:
print(f" ๐ Functions: {len(analysis_data['functions'])}")
for func in analysis_data['functions'][:3]: print(f" โข {func.get('name', 'unknown')} (line {func.get('line_number', '?')})")
if "structs" in analysis_data:
print(f" ๐ฆ Structs: {len(analysis_data['structs'])}")
for struct in analysis_data['structs'][:3]: print(f" โข {struct.get('name', 'unknown')} (line {struct.get('line_number', '?')})")
except json.JSONDecodeError:
content_preview = analyze_result.content[:200] + "..." if len(analyze_result.content) > 200 else analyze_result.content
print(f" {content_preview}")
except Exception as e:
print(f" โ ๏ธ analyze_file demo failed: {e}")
except Exception as e:
print(f"โ Error during scanning: {e}")
finally:
cleanup_sample_repository(temp_dir)
print("\n๐งน Sample repository cleaned up")
def create_sample_repository():
temp_dir = tempfile.mkdtemp(prefix="loregrep_example_")
base_path = Path(temp_dir)
python_file = base_path / "calculator.py"
python_file.write_text('''
"""
A simple calculator module demonstrating Python code parsing.
"""
def fibonacci(n):
"""Calculate the nth Fibonacci number."""
if n <= 1:
return n
return fibonacci(n-1) + fibonacci(n-2)
class Calculator:
"""A simple calculator class."""
def __init__(self):
self.history = []
def add(self, a, b):
"""Add two numbers."""
result = a + b
self.history.append(f"{a} + {b} = {result}")
return result
def multiply(self, a, b):
"""Multiply two numbers."""
result = a * b
self.history.append(f"{a} * {b} = {result}")
return result
def get_history(self):
"""Get calculation history."""
return self.history.copy()
''')
js_file = base_path / "utils.js"
js_file.write_text('''
/**
* Utility functions for various operations.
*/
function calculateSum(numbers) {
return numbers.reduce((sum, num) => sum + num, 0);
}
function findMax(numbers) {
return Math.max(...numbers);
}
class UserManager {
constructor() {
this.users = new Map();
}
addUser(id, name, email) {
this.users.set(id, { name, email, createdAt: new Date() });
}
getUser(id) {
return this.users.get(id);
}
getAllUsers() {
return Array.from(this.users.values());
}
deleteUser(id) {
return this.users.delete(id);
}
}
export { calculateSum, findMax, UserManager };
''')
rust_file = base_path / "config.rs"
rust_file.write_text('''
//! Configuration management module
//!
//! This module provides utilities for handling application configuration.
use std::collections::HashMap;
use std::fs;
use std::path::Path;
#[derive(Debug, Clone)]
pub struct Config {
pub name: String,
pub values: HashMap<String, String>,
}
impl Config {
pub fn new(name: &str) -> Self {
Self {
name: name.to_string(),
values: HashMap::new(),
}
}
pub fn set(&mut self, key: &str, value: &str) {
self.values.insert(key.to_string(), value.to_string());
}
pub fn get(&self, key: &str) -> Option<&String> {
self.values.get(key)
}
pub fn load_from_file<P: AsRef<Path>>(path: P) -> Result<Self, Box<dyn std::error::Error>> {
let content = fs::read_to_string(path)?;
// Simple key=value parser
let mut config = Config::new("loaded");
for line in content.lines() {
if let Some((key, value)) = line.split_once('=') {
config.set(key.trim(), value.trim());
}
}
Ok(config)
}
}
pub fn process_data(data: &[i32]) -> Vec<i32> {
data.iter()
.filter(|&&x| x > 0)
.map(|&x| x * 2)
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_config_creation() {
let config = Config::new("test");
assert_eq!(config.name, "test");
assert!(config.values.is_empty());
}
#[test]
fn test_process_data() {
let input = vec![-1, 0, 1, 2, 3];
let output = process_data(&input);
assert_eq!(output, vec![2, 4, 6]);
}
}
''')
subdir = base_path / "lib"
subdir.mkdir()
ts_file = subdir / "types.ts"
ts_file.write_text('''
/**
* Type definitions for the application
*/
export interface User {
id: number;
name: string;
email: string;
createdAt: Date;
}
export interface Config {
apiUrl: string;
timeout: number;
retries: number;
}
export class ApiClient {
private config: Config;
constructor(config: Config) {
this.config = config;
}
async fetchUser(id: number): Promise<User | null> {
try {
const response = await fetch(`${this.config.apiUrl}/users/${id}`);
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return await response.json();
} catch (error) {
console.error('Failed to fetch user:', error);
return null;
}
}
async createUser(userData: Omit<User, 'id' | 'createdAt'>): Promise<User | null> {
try {
const response = await fetch(`${this.config.apiUrl}/users`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(userData)
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return await response.json();
} catch (error) {
console.error('Failed to create user:', error);
return null;
}
}
}
export enum Status {
Pending = 'pending',
Success = 'success',
Error = 'error'
}
''')
return temp_dir
def cleanup_sample_repository(temp_dir):
import shutil
try:
shutil.rmtree(temp_dir)
except OSError:
pass
if __name__ == "__main__":
asyncio.run(main())