Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -153,14 +153,17 @@ jobs:
strategy:
matrix:
pyver: ['3.10', '3.11', '3.12', '3.13', '3.14']
os: [ubuntu]
os: ["ubuntu-latest"]
experimental: [false]
include:
- os: ubuntu
- os: "ubuntu-latest"
pyver: "3.14t"
experimental: false
- os: "ubuntu-24.04-arm"
pyver: "3.14"
experimental: false
fail-fast: true
runs-on: ${{ matrix.os }}-latest
runs-on: ${{ matrix.os }}
continue-on-error: ${{ matrix.experimental }}
permissions:
contents: read # For checkout
Expand All @@ -179,12 +182,12 @@ jobs:
allow-prereleases: true
python-version: ${{ matrix.pyver }}
- name: Install dependency for pyaudio (Ubuntu)
if: matrix.os == 'ubuntu'
if: startsWith(matrix.os, 'ubuntu')
run: |
sudo apt-get update
sudo apt-get install -y portaudio19-dev
- name: Install dependency for pyaudio (macOS)
if: matrix.os == 'macos'
if: startsWith(matrix.os, 'macos')
run: brew install portaudio
- name: Remove git LFS to avoid accidental large downloads
run: sudo rm -f /usr/bin/git-lfs
Expand Down
10 changes: 10 additions & 0 deletions dimos/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,12 @@ def _is_macos() -> bool:
return platform.system() == "Darwin"


def _no_sqlite_vec() -> bool:
# The aarch64 wheel ships a 32-bit binary ("wrong ELF class: ELFCLASS32"),
# and the macOS wheel fails to load via sqlite3 in CI.
return platform.machine() == "aarch64" or _is_macos()


def pytest_configure(config):
config.addinivalue_line("markers", "tool: dev tooling")
config.addinivalue_line(
Expand All @@ -92,6 +98,9 @@ def pytest_configure(config):
config.addinivalue_line("markers", "skipif_no_ros: skip when ROS dependencies are not present")
config.addinivalue_line("markers", "skipif_macos_bug: skip known-buggy tests on macOS")
config.addinivalue_line("markers", "skipif_macos: skip tests not intended to run on macOS")
config.addinivalue_line(
"markers", "skipif_no_sqlite_vec: skip when the sqlite-vec extension cannot be loaded"
)

if config.pluginmanager.hasplugin("_cov"):
os.environ["COVERAGE_PROCESS_START"] = str(config.rootpath / "pyproject.toml")
Expand Down Expand Up @@ -124,6 +133,7 @@ def pytest_collection_modifyitems(config, items):
"skipif_no_ros": (not _has_ros(), "ROS dependencies are not present"),
"skipif_macos_bug": (_is_macos(), "Some tests are buggy on Mac OS"),
"skipif_macos": (_is_macos(), "Not intended to run on macOS"),
"skipif_no_sqlite_vec": (_no_sqlite_vec(), "sqlite-vec extension not loadable here"),
}
for marker_name, (condition, reason) in _skipif_markers.items():
if condition:
Expand Down
7 changes: 7 additions & 0 deletions dimos/memory2/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

from __future__ import annotations

import platform
import sqlite3
import tempfile
from typing import TYPE_CHECKING, cast
Expand All @@ -28,6 +29,10 @@
from dimos.memory2.store.sqlite import SqliteStore
from dimos.models.embedding.clip import CLIPModel

# sqlite-vec fails to load on Linux ARM (32-bit binary in the aarch64 wheel)
# and on macOS in CI.
_SKIP_SQLITE_VEC = platform.machine() == "aarch64" or platform.system() == "Darwin"

if TYPE_CHECKING:
from collections.abc import Iterator
from pathlib import Path
Expand Down Expand Up @@ -55,6 +60,8 @@ def memory_session(memory_store: MemoryStore) -> Iterator[MemoryStore]:

@pytest.fixture
def sqlite_store() -> Iterator[SqliteStore]:
if _SKIP_SQLITE_VEC:
pytest.skip("sqlite-vec extension not loadable here")
with tempfile.NamedTemporaryFile(suffix=".db") as f:
store = SqliteStore(path=f.name)
with store:
Expand Down
4 changes: 4 additions & 0 deletions dimos/memory2/test_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ def test_qual_notifier(self) -> None:
assert qual(SubjectNotifier) == "dimos.memory2.notifier.subject.SubjectNotifier"


@pytest.mark.skipif_no_sqlite_vec
class TestRegistryStore:
def test_put_get_round_trip(self, tmp_path) -> None:
from dimos.memory2.utils.sqlite import open_sqlite_connection
Expand Down Expand Up @@ -106,6 +107,7 @@ def test_sqlite_blob_store_config(self) -> None:
restored = SqliteBlobStoreConfig(**dumped)
assert restored.path == "/tmp/test.db"

@pytest.mark.skipif_no_sqlite_vec
def test_sqlite_blob_store_roundtrip(self, tmp_path) -> None:
store = SqliteBlobStore(path=str(tmp_path / "blob.db"))
data = store.serialize()
Expand All @@ -127,6 +129,7 @@ def test_sqlite_vector_store_config(self) -> None:
restored = SqliteVectorStoreConfig(**dumped)
assert restored.path == "/tmp/vec.db"

@pytest.mark.skipif_no_sqlite_vec
def test_sqlite_vector_store_roundtrip(self, tmp_path) -> None:
store = SqliteVectorStore(path=str(tmp_path / "vec.db"))
data = store.serialize()
Expand Down Expand Up @@ -166,6 +169,7 @@ def test_backend_serialize(self, tmp_path) -> None:
assert data["notifier"]["class"] == qual(SubjectNotifier)


@pytest.mark.skipif_no_sqlite_vec
class TestStoreReopen:
def test_reopen_preserves_data(self, tmp_path) -> None:
"""Create a store, write data, close, reopen, read back."""
Expand Down
6 changes: 6 additions & 0 deletions dimos/memory2/test_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

from __future__ import annotations

import platform
from typing import TYPE_CHECKING, Any

import pytest
Expand All @@ -28,6 +29,8 @@
from dimos.memory2.blobstore.base import BlobStore
from dimos.memory2.vectorstore.base import VectorStore

_SKIP_SQLITE_VEC = platform.machine() == "aarch64" or platform.system() == "Darwin"

if TYPE_CHECKING:
from dimos.memory2.store.base import Store
Comment thread
Dreamsorcerer marked this conversation as resolved.

Expand Down Expand Up @@ -343,6 +346,8 @@ def memory_spy_session():

@pytest.fixture
def sqlite_spy_session(tmp_path):
if _SKIP_SQLITE_VEC:
pytest.skip("sqlite-vec extension not loadable here")
from dimos.memory2.store.sqlite import SqliteStore

blob_spy = SpyBlobStore()
Expand Down Expand Up @@ -417,6 +422,7 @@ def _emb(v: list[float]) -> Embedding:
assert results[0].data == "north"


@pytest.mark.skipif_no_sqlite_vec
class TestStandaloneComponents:
"""Verify each SQLite component works standalone with path= (no Store needed)."""

Expand Down
Loading