Skip to content

Commit c0538ad

Browse files
phernandezclaude
andauthored
perf: Optimize sync/indexing for 43% faster performance (#352)
Signed-off-by: phernandez <[email protected]> Co-authored-by: Claude <[email protected]>
1 parent cd5efd4 commit c0538ad

File tree

15 files changed

+758
-151
lines changed

15 files changed

+758
-151
lines changed

.github/workflows/test.yml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,6 @@ jobs:
6060
run: |
6161
just typecheck
6262
63-
- name: Run type checks
64-
run: |
65-
just typecheck
66-
6763
- name: Run linting
6864
run: |
6965
just lint

BUGFIX-project-delete.md

Lines changed: 0 additions & 80 deletions
This file was deleted.

CLAUDE.md

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,34 @@ See the [README.md](README.md) file for a project overview.
1414

1515
### Build and Test Commands
1616

17-
- Install: `make install` or `pip install -e ".[dev]"`
18-
- Run tests: `uv run pytest -p pytest_mock -v` or `make test`
17+
- Install: `just install` or `pip install -e ".[dev]"`
18+
- Run all tests (with coverage): `just test` - Runs both unit and integration tests with unified coverage
19+
- Run unit tests only: `just test-unit` - Fast, no coverage
20+
- Run integration tests only: `just test-int` - Fast, no coverage
21+
- Generate HTML coverage: `just coverage` - Opens in browser
1922
- Single test: `pytest tests/path/to/test_file.py::test_function_name`
20-
- Lint: `make lint` or `ruff check . --fix`
21-
- Type check: `make type-check` or `uv run pyright`
22-
- Format: `make format` or `uv run ruff format .`
23-
- Run all code checks: `make check` (runs lint, format, type-check, test)
24-
- Create db migration: `make migration m="Your migration message"`
25-
- Run development MCP Inspector: `make run-inspector`
23+
- Run benchmarks: `pytest test-int/test_sync_performance_benchmark.py -v -m "benchmark and not slow"`
24+
- Lint: `just lint` or `ruff check . --fix`
25+
- Type check: `just typecheck` or `uv run pyright`
26+
- Format: `just format` or `uv run ruff format .`
27+
- Run all code checks: `just check` (runs lint, format, typecheck, test)
28+
- Create db migration: `just migration "Your migration message"`
29+
- Run development MCP Inspector: `just run-inspector`
2630

27-
**Note:** Project supports Python 3.10+
31+
**Note:** Project requires Python 3.12+ (uses type parameter syntax and `type` aliases introduced in 3.12)
32+
33+
### Test Structure
34+
35+
- `tests/` - Unit tests for individual components (mocked, fast)
36+
- `test-int/` - Integration tests for real-world scenarios (no mocks, realistic)
37+
- Both directories are covered by unified coverage reporting
38+
- Benchmark tests in `test-int/` are marked with `@pytest.mark.benchmark`
39+
- Slow tests are marked with `@pytest.mark.slow`
2840

2941
### Code Style Guidelines
3042

3143
- Line length: 100 characters max
32-
- Python 3.12+ with full type annotations
44+
- Python 3.12+ with full type annotations (uses type parameters and type aliases)
3345
- Format with ruff (consistent styling)
3446
- Import order: standard lib, third-party, local imports
3547
- Naming: snake_case for functions/variables, PascalCase for classes
@@ -63,9 +75,11 @@ See the [README.md](README.md) file for a project overview.
6375
- Schema changes require Alembic migrations
6476
- SQLite is used for indexing and full text search, files are source of truth
6577
- Testing uses pytest with asyncio support (strict mode)
78+
- Unit tests (`tests/`) use mocks when necessary; integration tests (`test-int/`) use real implementations
6679
- Test database uses in-memory SQLite
67-
- Avoid creating mocks in tests in most circumstances.
68-
- Each test runs in a standalone environment with in memory SQLite and tmp_file directory
80+
- Each test runs in a standalone environment with in-memory SQLite and tmp_file directory
81+
- Performance benchmarks are in `test-int/test_sync_performance_benchmark.py`
82+
- Use pytest markers: `@pytest.mark.benchmark` for benchmarks, `@pytest.mark.slow` for slow tests
6983

7084
### Async Client Pattern (Important!)
7185

CONTRIBUTING.md

Lines changed: 80 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,18 @@ project and how to get started as a developer.
3434

3535
4. **Run the Tests**:
3636
```bash
37-
# Run all tests
37+
# Run all tests with unified coverage (unit + integration)
3838
just test
39-
# or
40-
uv run pytest -p pytest_mock -v
41-
39+
40+
# Run unit tests only (fast, no coverage)
41+
just test-unit
42+
43+
# Run integration tests only (fast, no coverage)
44+
just test-int
45+
46+
# Generate HTML coverage report
47+
just coverage
48+
4249
# Run a specific test
4350
pytest tests/path/to/test_file.py::test_function_name
4451
```
@@ -134,7 +141,7 @@ agreement to the DCO.
134141

135142
## Code Style Guidelines
136143

137-
- **Python Version**: Python 3.12+ with full type annotations
144+
- **Python Version**: Python 3.12+ with full type annotations (3.12+ required for type parameter syntax)
138145
- **Line Length**: 100 characters maximum
139146
- **Formatting**: Use ruff for consistent styling
140147
- **Import Order**: Standard lib, third-party, local imports
@@ -144,12 +151,78 @@ agreement to the DCO.
144151

145152
## Testing Guidelines
146153

147-
- **Coverage Target**: We aim for 100% test coverage for all code
154+
### Test Structure
155+
156+
Basic Memory uses two test directories with unified coverage reporting:
157+
158+
- **`tests/`**: Unit tests that test individual components in isolation
159+
- Fast execution with extensive mocking
160+
- Test individual functions, classes, and modules
161+
- Run with: `just test-unit` (no coverage, fast)
162+
163+
- **`test-int/`**: Integration tests that test real-world scenarios
164+
- Test full workflows with real database and file operations
165+
- Include performance benchmarks
166+
- More realistic but slower than unit tests
167+
- Run with: `just test-int` (no coverage, fast)
168+
169+
### Running Tests
170+
171+
```bash
172+
# Run all tests with unified coverage report
173+
just test
174+
175+
# Run only unit tests (fast iteration)
176+
just test-unit
177+
178+
# Run only integration tests
179+
just test-int
180+
181+
# Generate HTML coverage report
182+
just coverage
183+
184+
# Run specific test
185+
pytest tests/path/to/test_file.py::test_function_name
186+
187+
# Run tests excluding benchmarks
188+
pytest -m "not benchmark"
189+
190+
# Run only benchmark tests
191+
pytest -m benchmark test-int/test_sync_performance_benchmark.py
192+
```
193+
194+
### Performance Benchmarks
195+
196+
The `test-int/test_sync_performance_benchmark.py` file contains performance benchmarks that measure sync and indexing speed:
197+
198+
- `test_benchmark_sync_100_files` - Small repository performance
199+
- `test_benchmark_sync_500_files` - Medium repository performance
200+
- `test_benchmark_sync_1000_files` - Large repository performance (marked slow)
201+
- `test_benchmark_resync_no_changes` - Re-sync performance baseline
202+
203+
Run benchmarks with:
204+
```bash
205+
# Run all benchmarks (excluding slow ones)
206+
pytest test-int/test_sync_performance_benchmark.py -v -m "benchmark and not slow"
207+
208+
# Run all benchmarks including slow ones
209+
pytest test-int/test_sync_performance_benchmark.py -v -m benchmark
210+
211+
# Run specific benchmark
212+
pytest test-int/test_sync_performance_benchmark.py::test_benchmark_sync_100_files -v
213+
```
214+
215+
See `test-int/BENCHMARKS.md` for detailed benchmark documentation.
216+
217+
### Testing Best Practices
218+
219+
- **Coverage Target**: We aim for high test coverage for all code
148220
- **Test Framework**: Use pytest for unit and integration tests
149-
- **Mocking**: Use pytest-mock for mocking dependencies only when necessary
221+
- **Mocking**: Avoid mocking in integration tests; use sparingly in unit tests
150222
- **Edge Cases**: Test both normal operation and edge cases
151223
- **Database Testing**: Use in-memory SQLite for testing database operations
152224
- **Fixtures**: Use async pytest fixtures for setup and teardown
225+
- **Markers**: Use `@pytest.mark.benchmark` for benchmarks, `@pytest.mark.slow` for slow tests
153226

154227
## Release Process
155228

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[![License: AGPL v3](https://img.shields.io/badge/License-AGPL_v3-blue.svg)](https://www.gnu.org/licenses/agpl-3.0)
22
[![PyPI version](https://badge.fury.io/py/basic-memory.svg)](https://badge.fury.io/py/basic-memory)
3-
[![Python 3.13+](https://img.shields.io/badge/python-3.13+-blue.svg)](https://www.python.org/downloads/)
3+
[![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/downloads/)
44
[![Tests](https://github.com/basicmachines-co/basic-memory/workflows/Tests/badge.svg)](https://github.com/basicmachines-co/basic-memory/actions)
55
[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
66
![](https://badge.mcpx.dev?type=server 'MCP Server')

justfile

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,28 @@ install:
77
@echo ""
88
@echo "💡 Remember to activate the virtual environment by running: source .venv/bin/activate"
99

10-
# Run unit tests in parallel
10+
# Run unit tests only (fast, no coverage)
1111
test-unit:
12-
uv run pytest -p pytest_mock -v -n auto
12+
uv run pytest -p pytest_mock -v --no-cov -n auto tests
1313

14-
# Run integration tests in parallel
14+
# Run integration tests only (fast, no coverage)
1515
test-int:
1616
uv run pytest -p pytest_mock -v --no-cov -n auto test-int
1717

18-
# Run all tests
18+
# Run all tests with unified coverage report
1919
test: test-unit test-int
2020

21+
# Generate HTML coverage report
22+
coverage:
23+
uv run pytest -p pytest_mock -v -n auto tests test-int --cov-report=html
24+
@echo "Coverage report generated in htmlcov/index.html"
25+
2126
# Lint and fix code (calls fix)
2227
lint: fix
2328

2429
# Lint and fix code
2530
fix:
26-
uv run ruff check --fix --unsafe-fixes src tests
31+
uv run ruff check --fix --unsafe-fixes src tests test-int
2732

2833
# Type check code
2934
typecheck:

pyproject.toml

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name = "basic-memory"
33
dynamic = ["version"]
44
description = "Local-first knowledge management combining Zettelkasten with knowledge graphs"
55
readme = "README.md"
6-
requires-python = ">=3.12.1"
6+
requires-python = ">=3.12"
77
license = { text = "AGPL-3.0-or-later" }
88
authors = [
99
{ name = "Basic Machines", email = "[email protected]" }
@@ -54,16 +54,20 @@ build-backend = "hatchling.build"
5454
[tool.pytest.ini_options]
5555
pythonpath = ["src", "tests"]
5656
addopts = "--cov=basic_memory --cov-report term-missing"
57-
testpaths = ["tests"]
57+
testpaths = ["tests", "test-int"]
5858
asyncio_mode = "strict"
5959
asyncio_default_fixture_loop_scope = "function"
60+
markers = [
61+
"benchmark: Performance benchmark tests (deselect with '-m \"not benchmark\"')",
62+
"slow: Slow-running tests (deselect with '-m \"not slow\"')",
63+
]
6064

6165
[tool.ruff]
6266
line-length = 100
6367
target-version = "py312"
6468

65-
[tool.uv]
66-
dev-dependencies = [
69+
[dependency-groups]
70+
dev = [
6771
"gevent>=24.11.1",
6872
"icecream>=2.1.3",
6973
"pytest>=8.3.4",

src/basic_memory/ignore_utils.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@
1111
# Hidden files (files starting with dot)
1212
".*",
1313
# Basic Memory internal files
14-
"memory.db",
15-
"memory.db-shm",
16-
"memory.db-wal",
14+
"*.db",
15+
"*.db-shm",
16+
"*.db-wal",
1717
"config.json",
1818
# Version control
1919
".git",
@@ -84,10 +84,10 @@ def create_default_bmignore() -> None:
8484
# Hidden files (files starting with dot)
8585
.*
8686
87-
# Basic Memory internal files
88-
memory.db
89-
memory.db-shm
90-
memory.db-wal
87+
# Basic Memory internal files (includes test databases)
88+
*.db
89+
*.db-shm
90+
*.db-wal
9191
config.json
9292
9393
# Version control

0 commit comments

Comments
 (0)