From 4cb568c32604b712fec50ba7f91c50c78e078618 Mon Sep 17 00:00:00 2001 From: MatMoul Date: Sun, 10 May 2026 00:00:56 +0200 Subject: [PATCH] fix: default bridge and tests to project venv Python Use .venv/bin/python3 by default, with PYTHON_PATH as an override, and update the setup script and docs to match the new virtualenv-based workflow. --- .memory/project.md | 78 ++++++++--------------------- README.md | 5 +- package.json | 2 +- src/keepass.ts | 2 +- tests/integration/pykeepass.test.ts | 6 +-- 5 files changed, 28 insertions(+), 65 deletions(-) diff --git a/.memory/project.md b/.memory/project.md index 47a9c1b..be385a0 100644 --- a/.memory/project.md +++ b/.memory/project.md @@ -1,58 +1,20 @@ -# kdbx-lib - -TypeScript wrapper around `pykeepass` for read-only access to KeePass `.kdbx` files. - -## Architecture - -- Public API: TypeScript -- Runtime backend: Python 3 -- Bridge: `src/python/bridge.py` -- Transport: JSON over stdin/stdout -- Backend library: `pykeepass` - -## Requirements - -- Node.js or Bun -- Python 3 -- `pykeepass` installed in the Python environment used by the bridge -- A project-local `.venv` works well - -## Python setup - -Install dependencies with: - -```bash -bun run setup:python -``` - -Manual alternative: - -```bash -python3 -m pip install pykeepass -``` - -## Core behavior - -- Read-only library; it does not modify databases. -- `openKeePassDatabase(path, options)` opens a database through the Python bridge. -- `listEntries()` returns all entry fields exposed by the bridge: `title`, `username`, `password`, `url`, `notes`, `groupPath`, and `otp` when present. -- `findEntries(query)` performs partial matching and returns full entries. -- `listGroups()` returns group names and paths. -- `close()` is currently a no-op. - -## Fixture facts - -- Bundled fixtures: `tests/fixtures/data.kdbx` and `tests/fixtures/empty.kdbx` -- Fixture passwords and expected content live in companion JSON files -- `data.kdbx` contains four entries: `root`, `otp1`, `f1-item1`, `f2-item1` -- The fixture tree is `Racine/ -> root, otp1, Folder1/ -> f1-item1, Folder2/ -> f2-item1` -- Integration tests cover entries, groups, and the `otp1` OTP/TOTP value -- Canonical OTP value is the full `otpauth://...` URI returned by `pykeepass` - -## Notes - -- The bridge currently launches a Python process per call; simple but expensive. -- Errors from the bridge are propagated to TypeScript, including exit code when available. -- The API is still flatter than the real KeePass model. -- More failure-path tests are needed. -- Future improvement: a persistent Python process if performance becomes important. +{ + "name": "kdbx-lib", + "packageManager": "bun@1.0.0", + "version": "0.1.0", + "private": true, + "type": "module", + "scripts": { + "example": "bun run src/example.ts", + "validate": "bun run test", + "test": "bun test", + "test:unit": "bun test", + "test:integration": "bun run src/test-integration.ts", + "setup:python": "python3 -m venv .venv && .venv/bin/pip install pykeepass" + }, + "dependencies": {}, + "devDependencies": { + "typescript": "^5.5.0", + "bun-types": "^1.1.0" + } +} diff --git a/README.md b/README.md index 67667d7..5981297 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ The TypeScript layer launches a Python bridge and exchanges JSON through stdin/s - Node.js or Bun - Python 3 - `pykeepass` installed in the Python environment used by the bridge (the project provides `bun run setup:python`) +- The bridge defaults to `.venv/bin/python3` when available, or you can override with `PYTHON_PATH` ## Python setup @@ -28,10 +29,10 @@ bun run setup:python If you prefer manual installation: ```bash -python3 -m pip install pykeepass +python3 -m venv .venv && .venv/bin/pip install pykeepass ``` -The bridge also works with a project-local virtual environment such as `.venv` if you want to pin Python dependencies. +The bridge also works with a project-local virtual environment such as `.venv` and the tests will use it when present. ## Usage diff --git a/package.json b/package.json index eafb5ac..589d5cc 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "test": "bun test", "test:unit": "bun test", "test:integration": "bun run src/test-integration.ts", - "setup:python": "python3 -m pip install pykeepass" + "setup:python": "test -x .venv/bin/python3 || python3 -m venv .venv && .venv/bin/pip install pykeepass" }, "dependencies": {}, "devDependencies": { diff --git a/src/keepass.ts b/src/keepass.ts index 5495a7b..39756fd 100644 --- a/src/keepass.ts +++ b/src/keepass.ts @@ -13,7 +13,7 @@ export class KeePassDatabase { constructor( private readonly path: string, private readonly options: KeePassOpenOptions, - private readonly pythonPath = "python3", + private readonly pythonPath = process.env.PYTHON_PATH ?? ".venv/bin/python3", private readonly bridgePath = new URL("./python/bridge.py", import.meta.url) ) {} diff --git a/tests/integration/pykeepass.test.ts b/tests/integration/pykeepass.test.ts index 9180cdf..a7c2d49 100644 --- a/tests/integration/pykeepass.test.ts +++ b/tests/integration/pykeepass.test.ts @@ -26,7 +26,8 @@ const FIXTURE_PATH = "tests/fixtures/data.kdbx"; const FIXTURE_DATA_PATH = "tests/fixtures/data.kdbx.json"; async function ensurePyKeePass(): Promise { - const child = Bun.spawn(["python3", "-c", "import pykeepass; print('ok')"], { + const python = process.env.PYTHON_PATH ?? ".venv/bin/python3"; + const child = Bun.spawn([python, "-c", "import pykeepass; print('ok')"], { stdout: "pipe", stderr: "pipe", }); @@ -95,7 +96,7 @@ test("lists the groups from the bundled data fixture", async () => { } const db = openKeePassDatabase(FIXTURE_PATH, { password }); -const groups = await db.listGroups(); + const groups = await db.listGroups(); expect(groups).toEqual([ { name: "Racine", path: "" }, { name: "Folder1", path: "Folder1" }, @@ -145,4 +146,3 @@ test("uses the JSON fixture content as the source of truth for expectations", as "\t\t- f2-item1", ]); }); -