coderag-ai 0.3.0__tar.gz → 0.3.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/PKG-INFO +4 -4
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/docs/install-macos.md +8 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/pyproject.toml +7 -4
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/embeddings/sentence_transformer.py +7 -2
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/localdb.py +34 -4
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/parsing/python.py +13 -3
- coderag_ai-0.3.2/tests/test_phase14_localdb.py +72 -0
- coderag_ai-0.3.0/tests/test_phase14_localdb.py +0 -35
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/.env.example +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/.gitignore +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/CODE_OF_CONDUCT.md +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/CONTRIBUTING.md +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/Dockerfile +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/LICENSE +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/Makefile +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/NOTICE +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/README.md +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/SECURITY.md +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/alembic.ini +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/docker/entrypoint.sh +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/docker-compose.yml +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/docs/adding-language.md +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/docs/adr/001-postgres-pgvector.md +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/docs/adr/002-structural-chunks.md +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/docs/adr/003-hybrid-search.md +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/docs/adr/004-tree-sitter.md +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/docs/adr/005-llm-provider-independence.md +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/docs/adr/006-repository-authorization.md +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/docs/adr/007-token-budgeting.md +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/docs/architecture.md +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/docs/claude-code.md +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/docs/evaluation.md +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/docs/licenses.md +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/docs/llm-providers.md +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/docs/retrieval.md +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/docs/security.md +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/docs/vscode-extension.md +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/examples/demo-repository/payments/__init__.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/examples/demo-repository/payments/api.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/examples/demo-repository/payments/auth.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/examples/demo-repository/payments/checkout_service.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/examples/demo-repository/payments/models.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/examples/demo-repository/payments/payment_repository.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/examples/demo-repository/payments/payment_service.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/examples/demo-repository/payments/retry_policy.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/examples/demo-repository/payments/users.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/examples/demo-repository/tests/test_payment_service.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/examples/demo-repository/tests/test_retry_policy.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/examples/eval/eval_dataset.json +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/scripts/gen_initial_migration.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/__init__.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/analyzers/__init__.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/analyzers/base.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/analyzers/flake8_adapter.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/analyzers/pylint_adapter.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/analyzers/workflow.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/api/__init__.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/api/app.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/api/dashboard.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/api/schemas.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/cli/__init__.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/cli/main.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/context/__init__.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/context/builder.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/context/package.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/core/__init__.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/core/config.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/core/logging.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/core/text.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/core/tokens.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/db/__init__.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/db/base.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/db/migrations/env.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/db/migrations/script.py.mako +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/db/migrations/versions/.gitkeep +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/db/migrations/versions/9a973932b94d_measure_baseline_tokens.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/db/migrations/versions/c8a40feeda41_initial_schema.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/db/models.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/embeddings/__init__.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/embeddings/base.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/embeddings/hashing.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/embeddings/pipeline.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/embeddings/registry.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/evaluation/__init__.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/evaluation/datasets.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/evaluation/harness.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/git/__init__.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/git/repo.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/indexing/__init__.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/indexing/ignore.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/indexing/indexer.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/llm/__init__.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/llm/anthropic.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/llm/base.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/llm/null.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/llm/registry.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/mcp_server.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/parsing/__init__.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/parsing/base.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/parsing/registry.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/retrieval/__init__.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/retrieval/base.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/retrieval/engine.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/retrieval/fusion.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/retrieval/graph.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/retrieval/lexical.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/retrieval/reranking.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/retrieval/semantic.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/retrieval/symbol.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/security/__init__.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/security/authz.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/security/secrets.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/service.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/src/coderag/telemetry.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/tests/__init__.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/tests/conftest.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/tests/test_phase0_db.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/tests/test_phase0_migrations.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/tests/test_phase10_analyzers.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/tests/test_phase11_dashboard.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/tests/test_phase12_mcp.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/tests/test_phase13_measure.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/tests/test_phase1_indexer.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/tests/test_phase1_parser.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/tests/test_phase2_cli.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/tests/test_phase2_retrieval.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/tests/test_phase3_embeddings.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/tests/test_phase3_semantic.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/tests/test_phase3_sentence_transformer.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/tests/test_phase4_graph.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/tests/test_phase5_context_db.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/tests/test_phase5_context_unit.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/tests/test_phase6_api.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/tests/test_phase6_ask.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/tests/test_phase6_llm.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/tests/test_phase7_eval.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/tests/test_phase8_incremental.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/tests/test_phase9_rerank.py +0 -0
- {coderag_ai-0.3.0 → coderag_ai-0.3.2}/tests/test_security_secrets.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: coderag-ai
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.2
|
|
4
4
|
Summary: Token-efficient, structure-aware Code Intelligence + RAG for private source repositories.
|
|
5
5
|
Project-URL: Homepage, https://github.com/galacticsurfer/coderag
|
|
6
6
|
Project-URL: Repository, https://github.com/galacticsurfer/coderag
|
|
@@ -32,8 +32,8 @@ Requires-Dist: pydantic>=2.7
|
|
|
32
32
|
Requires-Dist: rich>=13.7
|
|
33
33
|
Requires-Dist: sqlalchemy>=2.0.30
|
|
34
34
|
Requires-Dist: structlog>=24.1
|
|
35
|
-
Requires-Dist: tree-sitter-python
|
|
36
|
-
Requires-Dist: tree-sitter
|
|
35
|
+
Requires-Dist: tree-sitter-python>=0.23
|
|
36
|
+
Requires-Dist: tree-sitter>=0.23
|
|
37
37
|
Requires-Dist: typer>=0.12
|
|
38
38
|
Requires-Dist: uvicorn[standard]>=0.30
|
|
39
39
|
Provides-Extra: analyzers
|
|
@@ -50,7 +50,7 @@ Provides-Extra: embeddings
|
|
|
50
50
|
Requires-Dist: sentence-transformers>=3.0; extra == 'embeddings'
|
|
51
51
|
Provides-Extra: localdb
|
|
52
52
|
Requires-Dist: alembic>=1.13; extra == 'localdb'
|
|
53
|
-
Requires-Dist: pgserver>=0.1.4; extra == 'localdb'
|
|
53
|
+
Requires-Dist: pgserver>=0.1.4; (python_version < '3.13') and extra == 'localdb'
|
|
54
54
|
Provides-Extra: mcp
|
|
55
55
|
Requires-Dist: mcp>=2.0; extra == 'mcp'
|
|
56
56
|
Provides-Extra: metrics
|
|
@@ -23,6 +23,14 @@ Open a new terminal afterwards so your `PATH` updates.
|
|
|
23
23
|
|
|
24
24
|
### 2. Install CodeRAG
|
|
25
25
|
|
|
26
|
+
> **Python version:** the `localdb` extra needs **Python 3.9–3.12** (its bundled
|
|
27
|
+
> PostgreSQL has no wheels for 3.13+). On a newer default Python use
|
|
28
|
+
> `pipx install --python python3.12 "coderag-ai[mcp,localdb]"` (`brew install python@3.12`),
|
|
29
|
+
> or install without `localdb` and supply your own PostgreSQL.
|
|
30
|
+
|
|
31
|
+
> **Corporate network?** If install fails with `invalid peer certificate: UnknownIssuer`,
|
|
32
|
+
> your proxy re-signs TLS. Fix with `export UV_NATIVE_TLS=true` (uses the macOS keychain).
|
|
33
|
+
|
|
26
34
|
```bash
|
|
27
35
|
pipx install "coderag-ai[mcp,localdb]"
|
|
28
36
|
```
|
|
@@ -7,7 +7,7 @@ build-backend = "hatchling.build"
|
|
|
7
7
|
# command are both `coderag`. Plain "coderag" is taken on PyPI by an unrelated project,
|
|
8
8
|
# and "code-rag" is rejected as too similar (PyPI collapses -/_/. when comparing names).
|
|
9
9
|
name = "coderag-ai"
|
|
10
|
-
version = "0.3.
|
|
10
|
+
version = "0.3.2"
|
|
11
11
|
description = "Token-efficient, structure-aware Code Intelligence + RAG for private source repositories."
|
|
12
12
|
readme = "README.md"
|
|
13
13
|
requires-python = ">=3.12"
|
|
@@ -40,8 +40,8 @@ dependencies = [
|
|
|
40
40
|
"alembic>=1.13",
|
|
41
41
|
"psycopg[binary]>=3.1", # LGPL-3.0 — see docs/licenses.md
|
|
42
42
|
"pgvector>=0.3.0",
|
|
43
|
-
"tree-sitter>=0.
|
|
44
|
-
"tree-sitter-python>=0.
|
|
43
|
+
"tree-sitter>=0.23",
|
|
44
|
+
"tree-sitter-python>=0.23",
|
|
45
45
|
"typer>=0.12",
|
|
46
46
|
"rich>=13.7",
|
|
47
47
|
"httpx>=0.27",
|
|
@@ -60,7 +60,10 @@ analyzers = ["pylint>=3.2", "flake8>=7.1"]
|
|
|
60
60
|
# MCP server: lets Claude Code (and other MCP clients) call CodeRAG retrieval.
|
|
61
61
|
mcp = ["mcp>=2.0"]
|
|
62
62
|
# Rootless local PostgreSQL+pgvector — no Docker, Homebrew, or sudo required.
|
|
63
|
-
|
|
63
|
+
# pgserver only ships wheels for CPython 3.9–3.12, so the marker keeps the extra
|
|
64
|
+
# installable on newer interpreters (the `coderag localdb` command then explains
|
|
65
|
+
# what to do instead of the install failing outright).
|
|
66
|
+
localdb = ["pgserver>=0.1.4; python_version < '3.13'", "alembic>=1.13"]
|
|
64
67
|
# Development / testing.
|
|
65
68
|
dev = [
|
|
66
69
|
"pytest>=8.2",
|
|
@@ -21,13 +21,18 @@ class SentenceTransformerEmbeddingProvider(EmbeddingProvider):
|
|
|
21
21
|
except ImportError as exc: # pragma: no cover - optional dependency
|
|
22
22
|
raise RuntimeError(
|
|
23
23
|
"sentence-transformers is not installed. Install the 'embeddings' "
|
|
24
|
-
"extra: pip install 'coderag[embeddings]'"
|
|
24
|
+
"extra: pip install 'coderag-ai[embeddings]'"
|
|
25
25
|
) from exc
|
|
26
26
|
self._model = SentenceTransformer(model_name, device=device)
|
|
27
27
|
self.model_name = model_name
|
|
28
28
|
self.model_version = "st1"
|
|
29
29
|
self.batch_size = batch_size
|
|
30
|
-
|
|
30
|
+
dim = self._model.get_sentence_embedding_dimension()
|
|
31
|
+
if dim is None: # pragma: no cover - model without a fixed dimension
|
|
32
|
+
raise RuntimeError(
|
|
33
|
+
f"model {model_name!r} does not report an embedding dimension"
|
|
34
|
+
)
|
|
35
|
+
self.dimension = int(dim)
|
|
31
36
|
|
|
32
37
|
def embed_documents(self, texts: list[str]) -> list[list[float]]:
|
|
33
38
|
vectors = self._model.encode(
|
|
@@ -19,10 +19,21 @@ def _require_pgserver():
|
|
|
19
19
|
try:
|
|
20
20
|
import pgserver # noqa: PLC0415
|
|
21
21
|
except ImportError as exc: # pragma: no cover - optional dependency
|
|
22
|
+
import sys
|
|
23
|
+
|
|
24
|
+
if sys.version_info >= (3, 13):
|
|
25
|
+
raise RuntimeError(
|
|
26
|
+
f"`coderag localdb` needs pgserver, which has no wheels for Python "
|
|
27
|
+
f"{sys.version_info.major}.{sys.version_info.minor} (it supports 3.9–3.12).\n"
|
|
28
|
+
"Either install CodeRAG on Python 3.12:\n"
|
|
29
|
+
" pipx install --python python3.12 'coderag-ai[mcp,localdb]'\n"
|
|
30
|
+
"or run PostgreSQL yourself (Docker: `docker compose up -d db`, or "
|
|
31
|
+
"Homebrew: `brew install postgresql@16 pgvector`) and set "
|
|
32
|
+
"CODERAG_DATABASE_URL."
|
|
33
|
+
) from exc
|
|
22
34
|
raise RuntimeError(
|
|
23
35
|
"pgserver is not installed. Install the 'localdb' extra:\n"
|
|
24
|
-
" pipx install 'coderag[mcp,localdb]
|
|
25
|
-
"git+https://github.com/galacticsurfer/coderag'"
|
|
36
|
+
" pipx install 'coderag-ai[mcp,localdb]'"
|
|
26
37
|
) from exc
|
|
27
38
|
return pgserver
|
|
28
39
|
|
|
@@ -38,8 +49,27 @@ def start(pgdata: Path | str | None = None) -> str:
|
|
|
38
49
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
39
50
|
# cleanup_mode=None -> the postmaster keeps running after we exit.
|
|
40
51
|
server = pgserver.get_server(str(path), cleanup_mode=None)
|
|
41
|
-
server.
|
|
42
|
-
|
|
52
|
+
url = sqlalchemy_url(server.get_uri())
|
|
53
|
+
_ensure_vector_extension(url)
|
|
54
|
+
return url
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _ensure_vector_extension(url: str) -> None:
|
|
58
|
+
"""Create the pgvector extension over a normal connection.
|
|
59
|
+
|
|
60
|
+
Deliberately does NOT use pgserver's bundled ``psql`` binary: on macOS that
|
|
61
|
+
executable can fail to run (exit 127), which would break `localdb start` even
|
|
62
|
+
though the server itself is healthy. psycopg is already a dependency, so we
|
|
63
|
+
talk to the server the same way the rest of the application does.
|
|
64
|
+
"""
|
|
65
|
+
from sqlalchemy import create_engine, text
|
|
66
|
+
|
|
67
|
+
engine = create_engine(url)
|
|
68
|
+
try:
|
|
69
|
+
with engine.begin() as conn:
|
|
70
|
+
conn.execute(text("CREATE EXTENSION IF NOT EXISTS vector"))
|
|
71
|
+
finally:
|
|
72
|
+
engine.dispose()
|
|
43
73
|
|
|
44
74
|
|
|
45
75
|
def stop(pgdata: Path | str | None = None, timeout: float = 15.0) -> None:
|
|
@@ -34,9 +34,19 @@ class PythonParser(LanguageParser):
|
|
|
34
34
|
extensions = (".py",)
|
|
35
35
|
|
|
36
36
|
def __init__(self) -> None:
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
# The tree-sitter Python API changed at 0.22: `Language(ptr)` lost its
|
|
38
|
+
# `name` argument and `Parser.set_language()` was replaced by passing the
|
|
39
|
+
# language to the constructor. Support both so the package installs on
|
|
40
|
+
# any platform/version combination (0.21 has no arm64 macOS wheel).
|
|
41
|
+
try:
|
|
42
|
+
self._lang = Language(tspython.language()) # tree-sitter >= 0.22
|
|
43
|
+
except TypeError: # pragma: no cover - legacy tree-sitter 0.21
|
|
44
|
+
self._lang = Language(tspython.language(), "python") # type: ignore[call-overload]
|
|
45
|
+
try:
|
|
46
|
+
self._parser = Parser(self._lang) # tree-sitter >= 0.22
|
|
47
|
+
except TypeError: # pragma: no cover - legacy tree-sitter 0.21
|
|
48
|
+
self._parser = Parser()
|
|
49
|
+
self._parser.set_language(self._lang) # type: ignore[attr-defined]
|
|
40
50
|
|
|
41
51
|
def parse(self, module_qualified_name: str, source: str) -> ParseResult:
|
|
42
52
|
src = source.encode("utf-8")
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"""Rootless local Postgres helper (no Docker/sudo) — lifecycle correctness."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
|
|
7
|
+
pytest.importorskip("pgserver")
|
|
8
|
+
|
|
9
|
+
from coderag import localdb # noqa: E402
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def test_status_does_not_start_the_server(tmp_path):
|
|
13
|
+
"""A status check must never start a server (regression: it used to)."""
|
|
14
|
+
pgdata = tmp_path / "pgdata"
|
|
15
|
+
assert localdb.status(pgdata) is None # not running, nothing created
|
|
16
|
+
assert not (pgdata / "postmaster.pid").exists()
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def test_start_status_stop_lifecycle(tmp_path):
|
|
20
|
+
pgdata = tmp_path / "pgdata"
|
|
21
|
+
url = localdb.start(pgdata)
|
|
22
|
+
try:
|
|
23
|
+
assert url.startswith("postgresql+psycopg://")
|
|
24
|
+
pid = localdb.status(pgdata)
|
|
25
|
+
assert pid and pid > 0
|
|
26
|
+
finally:
|
|
27
|
+
localdb.stop(pgdata)
|
|
28
|
+
assert localdb.status(pgdata) is None # stays stopped
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def test_stale_pidfile_reports_not_running(tmp_path):
|
|
32
|
+
pgdata = tmp_path / "pgdata"
|
|
33
|
+
pgdata.mkdir()
|
|
34
|
+
(pgdata / "postmaster.pid").write_text("999999999\n") # impossible pid
|
|
35
|
+
assert localdb.status(pgdata) is None
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def test_start_does_not_shell_out_to_psql(tmp_path, monkeypatch):
|
|
39
|
+
"""Regression: the bundled `psql` binary can fail on macOS (exit 127).
|
|
40
|
+
|
|
41
|
+
`start()` must create the pgvector extension over a normal DB connection, so
|
|
42
|
+
the command works even when that executable is unusable.
|
|
43
|
+
"""
|
|
44
|
+
import pgserver
|
|
45
|
+
|
|
46
|
+
real_get_server = pgserver.get_server
|
|
47
|
+
|
|
48
|
+
def guarded(pgdata, cleanup_mode=None):
|
|
49
|
+
server = real_get_server(pgdata, cleanup_mode=cleanup_mode)
|
|
50
|
+
|
|
51
|
+
def boom(*a, **k):
|
|
52
|
+
raise AssertionError("start() must not invoke the bundled psql binary")
|
|
53
|
+
|
|
54
|
+
monkeypatch.setattr(server, "psql", boom, raising=False)
|
|
55
|
+
return server
|
|
56
|
+
|
|
57
|
+
monkeypatch.setattr(pgserver, "get_server", guarded)
|
|
58
|
+
|
|
59
|
+
pgdata = tmp_path / "pgdata"
|
|
60
|
+
url = localdb.start(pgdata)
|
|
61
|
+
try:
|
|
62
|
+
from sqlalchemy import create_engine, text
|
|
63
|
+
|
|
64
|
+
engine = create_engine(url)
|
|
65
|
+
with engine.connect() as conn:
|
|
66
|
+
got = conn.execute(
|
|
67
|
+
text("SELECT extversion FROM pg_extension WHERE extname='vector'")
|
|
68
|
+
).scalar()
|
|
69
|
+
engine.dispose()
|
|
70
|
+
assert got, "pgvector extension should have been created"
|
|
71
|
+
finally:
|
|
72
|
+
localdb.stop(pgdata)
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
"""Rootless local Postgres helper (no Docker/sudo) — lifecycle correctness."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
import pytest
|
|
6
|
-
|
|
7
|
-
pytest.importorskip("pgserver")
|
|
8
|
-
|
|
9
|
-
from coderag import localdb # noqa: E402
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def test_status_does_not_start_the_server(tmp_path):
|
|
13
|
-
"""A status check must never start a server (regression: it used to)."""
|
|
14
|
-
pgdata = tmp_path / "pgdata"
|
|
15
|
-
assert localdb.status(pgdata) is None # not running, nothing created
|
|
16
|
-
assert not (pgdata / "postmaster.pid").exists()
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
def test_start_status_stop_lifecycle(tmp_path):
|
|
20
|
-
pgdata = tmp_path / "pgdata"
|
|
21
|
-
url = localdb.start(pgdata)
|
|
22
|
-
try:
|
|
23
|
-
assert url.startswith("postgresql+psycopg://")
|
|
24
|
-
pid = localdb.status(pgdata)
|
|
25
|
-
assert pid and pid > 0
|
|
26
|
-
finally:
|
|
27
|
-
localdb.stop(pgdata)
|
|
28
|
-
assert localdb.status(pgdata) is None # stays stopped
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
def test_stale_pidfile_reports_not_running(tmp_path):
|
|
32
|
-
pgdata = tmp_path / "pgdata"
|
|
33
|
-
pgdata.mkdir()
|
|
34
|
-
(pgdata / "postmaster.pid").write_text("999999999\n") # impossible pid
|
|
35
|
-
assert localdb.status(pgdata) is None
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{coderag_ai-0.3.0 → coderag_ai-0.3.2}/examples/demo-repository/payments/payment_repository.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{coderag_ai-0.3.0 → coderag_ai-0.3.2}/examples/demo-repository/tests/test_payment_service.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|