Skip to content

Commit 3cde4fc

Browse files
committed
fix: Fix pre-commit issues and update tests
- Fix import sorting and unused imports - Update type annotations to use built-in types (list, dict) instead of typing.List/Dict - Fix trailing whitespace and end-of-file issues - Fix Chinese fullwidth comma to regular comma - Update test_main_cli.py to test_document_rag.py - Add backward compatibility test for main_cli_example.py - Pass all pre-commit hooks (ruff, ruff-format, etc.)
1 parent 4e3bcda commit 3cde4fc

10 files changed

Lines changed: 52 additions & 56 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ python ./examples/document_rag.py --query "What are the main techniques LEANN ex
195195
--embedding-model MODEL # e.g., facebook/contriever, text-embedding-3-small
196196
--embedding-mode MODE # sentence-transformers, openai, or mlx
197197

198-
# LLM Parameters
198+
# LLM Parameters
199199
--llm TYPE # openai, ollama, or hf
200200
--llm-model MODEL # e.g., gpt-4o, llama3.2:1b
201201
--top-k N # Number of results to retrieve (default: 20)

examples/PARAMETER_CONSISTENCY.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,4 @@ This document ensures that the new unified interface maintains exact parameter c
6161

6262
5. **Special Cases**:
6363
- WeChat uses a specific Chinese embedding model
64-
- Email reader includes HTML processing option
64+
- Email reader includes HTML processing option

examples/base_rag_example.py

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,12 @@
44
"""
55

66
import argparse
7-
import asyncio
8-
import os
9-
from pathlib import Path
10-
from typing import Optional, List, Dict, Any
117
from abc import ABC, abstractmethod
8+
from pathlib import Path
9+
from typing import Any
1210

1311
import dotenv
14-
from leann.api import LeannBuilder, LeannSearcher, LeannChat
12+
from leann.api import LeannBuilder, LeannChat
1513
from llama_index.core.node_parser import SentenceSplitter
1614

1715
dotenv.load_dotenv()
@@ -129,11 +127,11 @@ def _add_specific_arguments(self, parser: argparse.ArgumentParser):
129127
pass
130128

131129
@abstractmethod
132-
async def load_data(self, args) -> List[str]:
130+
async def load_data(self, args) -> list[str]:
133131
"""Load data from the source. Returns list of text chunks."""
134132
pass
135133

136-
def get_llm_config(self, args) -> Dict[str, Any]:
134+
def get_llm_config(self, args) -> dict[str, Any]:
137135
"""Get LLM configuration based on arguments."""
138136
config = {"type": args.llm}
139137

@@ -147,7 +145,7 @@ def get_llm_config(self, args) -> Dict[str, Any]:
147145

148146
return config
149147

150-
async def build_index(self, args, texts: List[str]) -> str:
148+
async def build_index(self, args, texts: list[str]) -> str:
151149
"""Build LEANN index from texts."""
152150
index_path = str(Path(args.index_dir) / f"{self.default_index_name}.leann")
153151

@@ -256,7 +254,7 @@ async def run(self):
256254
await self.run_interactive_chat(args, index_path)
257255

258256

259-
def create_text_chunks(documents, chunk_size=256, chunk_overlap=25) -> List[str]:
257+
def create_text_chunks(documents, chunk_size=256, chunk_overlap=25) -> list[str]:
260258
"""Helper function to create text chunks from documents."""
261259
node_parser = SentenceSplitter(
262260
chunk_size=chunk_size,

examples/browser_rag.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import os
77
import sys
88
from pathlib import Path
9-
from typing import List
109

1110
# Add parent directory to path for imports
1211
sys.path.insert(0, str(Path(__file__).parent))
@@ -52,7 +51,7 @@ def _get_chrome_base_path(self) -> Path:
5251
else:
5352
raise ValueError(f"Unsupported platform: {sys.platform}")
5453

55-
def _find_chrome_profiles(self) -> List[Path]:
54+
def _find_chrome_profiles(self) -> list[Path]:
5655
"""Auto-detect all Chrome profiles."""
5756
base_path = self._get_chrome_base_path()
5857
if not base_path.exists():
@@ -73,7 +72,7 @@ def _find_chrome_profiles(self) -> List[Path]:
7372

7473
return profiles
7574

76-
async def load_data(self, args) -> List[str]:
75+
async def load_data(self, args) -> list[str]:
7776
"""Load browser history and convert to text chunks."""
7877
# Determine Chrome profiles
7978
if args.chrome_profile and not args.auto_find_profiles:

examples/document_rag.py

Lines changed: 22 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
import sys
77
from pathlib import Path
8-
from typing import List
98

109
# Add parent directory to path for imports
1110
sys.path.insert(0, str(Path(__file__).parent))
@@ -16,84 +15,76 @@
1615

1716
class DocumentRAG(BaseRAGExample):
1817
"""RAG example for document processing (PDF, TXT, MD, etc.)."""
19-
18+
2019
def __init__(self):
2120
super().__init__(
2221
name="Document",
2322
description="Process and query documents (PDF, TXT, MD, etc.) with LEANN",
24-
default_index_name="test_doc_files" # Match original main_cli_example.py default
23+
default_index_name="test_doc_files", # Match original main_cli_example.py default
2524
)
26-
25+
2726
def _add_specific_arguments(self, parser):
2827
"""Add document-specific arguments."""
29-
doc_group = parser.add_argument_group('Document Parameters')
28+
doc_group = parser.add_argument_group("Document Parameters")
3029
doc_group.add_argument(
3130
"--data-dir",
3231
type=str,
3332
default="examples/data",
34-
help="Directory containing documents to index (default: examples/data)"
33+
help="Directory containing documents to index (default: examples/data)",
3534
)
3635
doc_group.add_argument(
3736
"--file-types",
3837
nargs="+",
3938
default=[".pdf", ".txt", ".md"],
40-
help="File types to process (default: .pdf .txt .md)"
39+
help="File types to process (default: .pdf .txt .md)",
4140
)
4241
doc_group.add_argument(
43-
"--chunk-size",
44-
type=int,
45-
default=256,
46-
help="Text chunk size (default: 256)"
42+
"--chunk-size", type=int, default=256, help="Text chunk size (default: 256)"
4743
)
4844
doc_group.add_argument(
49-
"--chunk-overlap",
50-
type=int,
51-
default=128,
52-
help="Text chunk overlap (default: 128)"
45+
"--chunk-overlap", type=int, default=128, help="Text chunk overlap (default: 128)"
5346
)
54-
55-
async def load_data(self, args) -> List[str]:
47+
48+
async def load_data(self, args) -> list[str]:
5649
"""Load documents and convert to text chunks."""
5750
print(f"Loading documents from: {args.data_dir}")
5851
print(f"File types: {args.file_types}")
59-
52+
6053
# Check if data directory exists
6154
data_path = Path(args.data_dir)
6255
if not data_path.exists():
6356
raise ValueError(f"Data directory not found: {args.data_dir}")
64-
57+
6558
# Load documents
6659
documents = SimpleDirectoryReader(
6760
args.data_dir,
6861
recursive=True,
6962
encoding="utf-8",
7063
required_exts=args.file_types,
7164
).load_data(show_progress=True)
72-
65+
7366
if not documents:
7467
print(f"No documents found in {args.data_dir} with extensions {args.file_types}")
7568
return []
76-
69+
7770
print(f"Loaded {len(documents)} documents")
78-
71+
7972
# Convert to text chunks
8073
all_texts = create_text_chunks(
81-
documents,
82-
chunk_size=args.chunk_size,
83-
chunk_overlap=args.chunk_overlap
74+
documents, chunk_size=args.chunk_size, chunk_overlap=args.chunk_overlap
8475
)
85-
76+
8677
# Apply max_items limit if specified
8778
if args.max_items > 0 and len(all_texts) > args.max_items:
8879
print(f"Limiting to {args.max_items} chunks (from {len(all_texts)})")
89-
all_texts = all_texts[:args.max_items]
90-
80+
all_texts = all_texts[: args.max_items]
81+
9182
return all_texts
9283

9384

9485
if __name__ == "__main__":
9586
import asyncio
96-
87+
9788
# Example queries for document RAG
9889
print("\n📄 Document RAG Example")
9990
print("=" * 50)
@@ -102,6 +93,6 @@ async def load_data(self, args) -> List[str]:
10293
print("- 'Summarize the key findings in these papers'")
10394
print("- 'What is the storage reduction achieved by LEANN?'")
10495
print("\nOr run without --query for interactive mode\n")
105-
96+
10697
rag = DocumentRAG()
107-
asyncio.run(rag.run())
98+
asyncio.run(rag.run())

examples/email_rag.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,8 @@
33
Supports Apple Mail on macOS.
44
"""
55

6-
import os
76
import sys
87
from pathlib import Path
9-
from typing import List
108

119
# Add parent directory to path for imports
1210
sys.path.insert(0, str(Path(__file__).parent))
@@ -39,7 +37,7 @@ def _add_specific_arguments(self, parser):
3937
"--include-html", action="store_true", help="Include HTML content in email processing"
4038
)
4139

42-
def _find_mail_directories(self) -> List[Path]:
40+
def _find_mail_directories(self) -> list[Path]:
4341
"""Auto-detect all Apple Mail directories."""
4442
mail_base = Path.home() / "Library" / "Mail"
4543
if not mail_base.exists():
@@ -53,7 +51,7 @@ def _find_mail_directories(self) -> List[Path]:
5351

5452
return messages_dirs
5553

56-
async def load_data(self, args) -> List[str]:
54+
async def load_data(self, args) -> list[str]:
5755
"""Load emails and convert to text chunks."""
5856
# Determine mail directories
5957
if args.mail_path:

examples/main_cli_example.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
"""
66

77
import sys
8-
import os
98

109
print("=" * 70)
1110
print("NOTICE: This script has been replaced!")

examples/wechat_rag.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import subprocess
77
import sys
88
from pathlib import Path
9-
from typing import List
109

1110
# Add parent directory to path for imports
1211
sys.path.insert(0, str(Path(__file__).parent))
@@ -84,7 +83,7 @@ def _export_wechat_data(self, export_dir: Path) -> bool:
8483
print(f"Export error: {e}")
8584
return False
8685

87-
async def load_data(self, args) -> List[str]:
86+
async def load_data(self, args) -> list[str]:
8887
"""Load WeChat history and convert to text chunks."""
8988
export_path = Path(args.export_dir)
9089

@@ -145,7 +144,7 @@ async def load_data(self, args) -> List[str]:
145144
print("\nExample queries you can try:")
146145
print("- 'Show me conversations about travel plans'")
147146
print("- 'Find group chats about weekend activities'")
148-
print("- '我想买魔术师约翰逊的球衣给我一些对应聊天记录?'")
147+
print("- '我想买魔术师约翰逊的球衣,给我一些对应聊天记录?'")
149148
print("- 'What did we discuss about the project last month?'")
150149
print("\nNote: WeChat must be running for export to work\n")
151150

tests/test_document_rag.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ def test_document_rag_simulated(test_data_dir):
5353

5454
# Verify output
5555
output = result.stdout + result.stderr
56-
assert "Leann index built at" in output or "Using existing index" in output
56+
assert "Index saved to" in output or "Using existing index" in output
5757
assert "This is a simulated answer" in output
5858

5959

@@ -117,4 +117,16 @@ def test_document_rag_error_handling(test_data_dir):
117117

118118
# Should fail with invalid LLM type
119119
assert result.returncode != 0
120-
assert "Unknown LLM type" in result.stderr or "invalid_llm_type" in result.stderr
120+
assert "invalid choice" in result.stderr or "invalid_llm_type" in result.stderr
121+
122+
123+
def test_main_cli_backward_compatibility():
124+
"""Test that main_cli_example.py shows migration message."""
125+
cmd = [sys.executable, "examples/main_cli_example.py", "--help"]
126+
127+
result = subprocess.run(cmd, capture_output=True, text=True, timeout=60)
128+
129+
# Should exit with error code and show migration message
130+
assert result.returncode != 0
131+
assert "This script has been replaced" in result.stdout
132+
assert "document_rag.py" in result.stdout

0 commit comments

Comments
 (0)