Skip to content

fix: remove undeclared dotenv dependency from KG rebuild - #637

Merged
EtanHey merged 1 commit into
mainfrom
fix/ci-unblock
Aug 1, 2026
Merged

fix: remove undeclared dotenv dependency from KG rebuild#637
EtanHey merged 1 commit into
mainfrom
fix/ci-unblock

Conversation

@EtanHey

@EtanHey EtanHey commented Aug 1, 2026

Copy link
Copy Markdown
Owner

Summary\n- remove the import-time python-dotenv dependency from scripts/kg_rebuild.py\n- add a regression test proving the KG rebuild helper imports when python-dotenv is unavailable\n\n## Root causes\n- #631 test (3.11): scripts/kg_rebuild.py imported python-dotenv at module load even though it is not a declared dependency\n- #634 test (3.11): the same import-time python-dotenv failure\n- #634 lint: Ruff 0.16.1 wants the branch-only t3_health_path assignment in src/brainlayer/health_check.py formatted on one line; this does not exist on main and will be fixed on that branch after this PR lands\n- #635 test (3.13): the same import-time python-dotenv failure, not a separate Python 3.13 incompatibility\n\nThis chooses option (b): the unit test should not require dotenv. The Groq extraction path already reads GROQ_API_KEY from the process environment and has its own dependency-free repo .env fallback, so loading .env at module import was redundant and made pure helper imports depend on an undeclared package.\n\n## Verification\n- Python 3.11: tests/test_kg_rebuild.py — 20 passed\n- Python 3.13: tests/test_kg_rebuild.py — 20 passed\n- Python 3.12 repository pre-push gate:\n - unit suite — 3641 passed, 9 skipped, 61 deselected, 1 xfailed\n - MCP registration — 3 passed\n - isolated eval/hook routing — 40 passed\n - Bun stale-index test — passed\n - FTS5 determinism shell regression — passed\n- Ruff 0.16.1 check and format check — passed\n\nReview routing is intentionally left to @brainlayer.


Note

Low Risk
Small dependency/import cleanup with a regression test; no change to KG extraction logic or Groq env loading at runtime.

Overview
Removes import-time python-dotenv loading from scripts/kg_rebuild.py so importing the module (including pure helpers like extracted_entity_from_groq_payload in tests) no longer depends on an undeclared package.

Groq Tier 2 behavior is unchanged: call_groq_ner still reads GROQ_API_KEY from the process environment and can fall back to parsing the repo .env without dotenv.

Adds test_kg_rebuild_module_import_does_not_require_python_dotenv, which blocks dotenv imports and asserts scripts.kg_rebuild still loads successfully.

Reviewed by Cursor Bugbot for commit 955e57e. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Remove undeclared python-dotenv dependency from scripts/kg_rebuild.py

Removes the dotenv.load_dotenv import and the .env file load from kg_rebuild.py, which was failing for users without python-dotenv installed. A regression test in test_kg_rebuild.py verifies the module imports cleanly when dotenv is unavailable.

Macroscope summarized 955e57e.

Summary by CodeRabbit

  • Bug Fixes

    • Improved knowledge graph rebuild startup by removing reliance on automatic .env loading.
    • The rebuild process can now initialize successfully when the optional environment-loading package is unavailable.
  • Tests

    • Added regression coverage to verify successful module loading and entity extraction functionality.

@cursor

cursor Bot commented Aug 1, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_ceeab423-fcf5-4f55-8ac9-5237035867a2)

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The KG rebuild script no longer loads .env during startup. A regression test blocks dotenv imports and confirms that scripts.kg_rebuild imports successfully with its extraction function available.

Changes

KG rebuild import behavior

Layer / File(s) Summary
Remove startup dotenv loading
scripts/kg_rebuild.py, tests/test_kg_rebuild.py
The script no longer loads .env at import time. The test verifies import success when python-dotenv is unavailable and confirms that extracted_entity_from_groq_payload remains callable.

Estimated code review effort: 2 (Simple) | ~10 minutes

Poem

I’m a rabbit guarding the build,
No .env is loaded or spilled.
Dotenv may hide,
The import still runs wide,
And the extractor stands skilled.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: removing the undeclared dotenv dependency from the KG rebuild script.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/ci-unblock

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 955e57e966

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/kg_rebuild.py

load_dotenv(Path(__file__).resolve().parent.parent / ".env")

from brainlayer.paths import get_db_path

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve the configured database before rebuilding

When a developer keeps BRAINLAYER_DB in the repo .env, removing this load makes main() silently fall back to the canonical database via get_db_path(). Running either rebuild tier then writes entities and relations to the live canonical DB instead of the configured sandbox/custom DB; replace the dotenv dependency with dependency-free loading that preserves the prior override, or require an explicit DB argument rather than silently changing targets.

AGENTS.md reference: AGENTS.md:L5-L8

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/test_kg_rebuild.py`:
- Around line 327-329: Update the import-check test around the direct
sys.modules.pop and importlib.import_module calls to save the existing
scripts.kg_rebuild module and parent-package attribute, then restore both in a
finally block even when the import fails. Preserve the import-hook validation
while preventing this test from leaving process-wide module state altered.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 82e8ccce-f3e8-40ad-8f42-4947e0c72327

📥 Commits

Reviewing files that changed from the base of the PR and between 4038048 and 955e57e.

📒 Files selected for processing (2)
  • scripts/kg_rebuild.py
  • tests/test_kg_rebuild.py
💤 Files with no reviewable changes (1)
  • scripts/kg_rebuild.py
📜 Review details
⏰ Context from checks skipped due to timeout. (3)
  • GitHub Check: test (3.12)
  • GitHub Check: test (3.11)
  • GitHub Check: test (3.13)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Flag risky DB or concurrency changes explicitly and do not hand-wave lock behavior
Enforce one-write-at-a-time concurrency constraint; reads are safe but brain_digest is write-heavy and must not run in parallel with other MCP work
Run pytest before claiming behavior changed safely; current test suite has 929 tests

Files:

  • tests/test_kg_rebuild.py
tests/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Tests must not refresh the production backup heartbeat log; use BRAINLAYER_BACKUP_LOG_PATH and set provenance to pytest.

Files:

  • tests/test_kg_rebuild.py
🔇 Additional comments (1)
tests/test_kg_rebuild.py (1)

314-329: 🗄️ Data Integrity & Integration

No change needed.

scripts.kg_rebuild imports do not trigger the production backup heartbeat log, so setting BRAINLAYER_BACKUP_LOG_PATH or provenance before this import is not needed.

			> Likely an incorrect or invalid review comment.

Comment thread tests/test_kg_rebuild.py
Comment on lines +327 to +329
sys.modules.pop("scripts.kg_rebuild", None)

module = importlib.import_module("scripts.kg_rebuild")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== files =="
git ls-files | rg '(^|/)tests/test_kg_rebuild\.py$|(^|/)scripts/kg_rebuild\.py$|(^|/)pytest|\.ini$|pyproject\.toml' || true

echo "== relevant test section =="
if [ -f tests/test_kg_rebuild.py ]; then
  nl -ba tests/test_kg_rebuild.py | sed -n '280,360p'
fi

echo "== references to monkeypatch/sys.modules/import hook and scripts.kg_rebuild =="
rg -n "builtins\.__import__|sys\.modules\['scripts\.kg_rebuild'\]|sys\.modules\.pop|importlib\.import_module|scripts\.kg_rebuild|BRAINLAYER_BACKUP_LOG_PATH|pytest" tests/test_kg_rebuild.py | sed -n '1,220p'

Repository: EtanHey/brainlayer

Length of output: 298


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
import os, re
for path in ["tests/test_kg_rebuild.py", "scripts/kg_rebuild.py"]:
    print(f"== {path} size/exists ==")
    print(f"exists={os.path.exists(path)}")
    if os.path.exists(path):
        with open(path, encoding="utf-8") as f:
            lines = f.read().splitlines()
        print(f"lines={len(lines)}")
        start=max(1,280) if path=="tests/test_kg_rebuild.py" else 1
        end=min(len(lines),360) if path=="tests/test_kg_rebuild.py" else 170
        for i in range(start,min(end+1,len(lines))+1):
            print(f"{i:04d}\t{lines[i-1]}")
PY

echo "== focused references =="
rg -n "builtins\.__import__|sys\.modules\['scripts\.kg_rebuild'\]|sys\.modules\.pop|importlib\.import_module|scripts\.kg_rebuild|BRAINLAYER_BACKUP_LOG_PATH|pytest|monkeypatch" tests/test_kg_rebuild.py | head -n 220 || true

echo "== pytest config =="
for f in pyproject.toml pytest.ini; do
  if [ -f "$f" ]; then
    echo "--- $f ---"
    sed -n '1,220p' "$f"
  fi
done

Repository: EtanHey/brainlayer

Length of output: 14148


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
import ast
from pathlib import Path

path = Path("tests/test_kg_rebuild.py")
src = path.read_text(encoding="utf-8")
tree = ast.parse(src)

for node in ast.walk(tree):
    if isinstance(node, ast.ClassDef) or isinstance(node, ast.FunctionDef) or isinstance(node, ast.AsyncFunctionDef):
        if "test_" in str(node.name):
            print(f"Function {node.name} at lines {node.lineno}-{getattr(node, 'end_lineno', '?')}")

test = next(n for n in tree.body if isinstance(n, ast.FunctionDef) and n.name == "test_kg_rebuild_module_import_does_not_require_python_dotenv")

print("\nBody nodes:")
for n in test.body:
    print(type(n).__name__, getattr(n, "lineno", "?"), getattr(n, "end_lineno", "?"), ast.unparse(n)[:260])

print("\nsys.modules.pop occurrences:")
for n in ast.walk(test):
    if isinstance(n, ast.Call):
        func = n.func
        if isinstance(getattr(func, "value", None), ast.Attribute) and getattr(func, "attr", None) == "pop":
            print(ast.unparse(n))

print("\nsys.modules.pop with cleanup occurrences:")
for n in ast.walk(test):
    if isinstance(n, ast.Try):
        for stmt in n.body:
            print("try body first:", ast.unparse(stmt)[:240])
        cleanup = []
        for h in n.handlers:
            for stmt in h.body:
                cleanup.append(ast.unparse(stmt)[:240])
        for stmt in n.finalbody:
            cleanup.append(ast.unparse(stmt)[:240])
        if any("sys.modules" in s or "builtins" in s for s in cleanup):
            print("cleanup:")
            for s in cleanup:
                print("  " + s)
PY

Repository: EtanHey/brainlayer

Length of output: 2051


Restore scripts.kg_rebuild after checking the import hook.

monkeypatch restores builtins.__import__, but it does not restore the direct sys.modules.pop("scripts.kg_rebuild", None). If another test loaded scripts.kg_rebuild first, this test replaces it process-wide; an import failure then leaves it removed. Restore the previous module entry and parent package attribute in a finally block, or run this import check in a separate process.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_kg_rebuild.py` around lines 327 - 329, Update the import-check
test around the direct sys.modules.pop and importlib.import_module calls to save
the existing scripts.kg_rebuild module and parent-package attribute, then
restore both in a finally block even when the import fails. Preserve the
import-hook validation while preventing this test from leaving process-wide
module state altered.

@EtanHey
EtanHey merged commit e6bd25d into main Aug 1, 2026
9 checks passed
@EtanHey
EtanHey deleted the fix/ci-unblock branch August 1, 2026 21:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant