============================= test session starts ==============================
platform darwin -- Python 3.13.7, pytest-9.0.1, pluggy-1.6.0
rootdir: /Users/davidahmann/Projects/meridian_oss
configfile: pytest.ini (WARNING: ignoring pytest config in pyproject.toml!)
plugins: anyio-4.12.0, asyncio-1.3.0
asyncio: mode=Mode.STRICT, debug=False, asyncio_default_fixture_loop_scope=None, asyncio_default_test_loop_scope=function
collected 2 items

tests/integration/test_offline_flow.py Offline retrieval failed: Binder Error: Referenced table "e" not found!
Candidate tables: "entity_df"
F2025-12-05 07:52:58 [info     ] materialize_start              feature=is_high_value
2025-12-05 07:52:58 [error    ] materialize_failed             error='asyncio.run() cannot be called from a running event loop' feature=is_high_value
F

=================================== FAILURES ===================================
________________________ test_hybrid_offline_retrieval _________________________

    @pytest.mark.asyncio
    async def test_hybrid_offline_retrieval() -> None:
        # 1. Setup Stores
        # Create a DuckDB store with some data
        offline_store = DuckDBOfflineStore()
        offline_store.conn.execute("CREATE TABLE user_stats (entity_id VARCHAR, total_spend INTEGER)")
        offline_store.conn.execute("INSERT INTO user_stats VALUES ('u1', 100), ('u2', 200)")

        store = FeatureStore(
            offline_store=offline_store,
            online_store=InMemoryOnlineStore()
        )

        @entity(store)
        class User:
            user_id: str

        # 2. Define Features
        # Python Feature
        @feature(entity=User)
        def name_len(user_id: str) -> int:
            return len(user_id)

        # SQL Feature
        # Note: We assume the table name matches the feature name for the MVP join logic
        # OR we need to adjust the test to match the MVP implementation.
        # In MVP DuckDBOfflineStore, we do: LEFT JOIN {feature} ON ...
        # So we need a table named 'total_spend' if the feature is named 'total_spend'.
        # Let's rename the table to match the feature.
        offline_store.conn.execute("ALTER TABLE user_stats RENAME TO total_spend")

        @feature(entity=User, sql="SELECT * FROM total_spend")
        def total_spend(user_id: str) -> int:
            return 0 # Stub for Python, but SQL should take precedence in retrieval

        # 3. Create Entity DataFrame
        entity_df = pd.DataFrame({"user_id": ["u1", "u2"]})

        # 4. Get Training Data
        training_df = await store.get_training_data(entity_df, ["name_len", "total_spend"])

        # 5. Verify Results
        assert "name_len" in training_df.columns
>       assert "total_spend" in training_df.columns
E       AssertionError: assert 'total_spend' in Index(['user_id', 'name_len'], dtype='object')
E        +  where Index(['user_id', 'name_len'], dtype='object') =   user_id  name_len\n0      u1         2\n1      u2         2.columns

tests/integration/test_offline_flow.py:50: AssertionError
__________________________ test_materialization_flow ___________________________

    @pytest.mark.asyncio
    async def test_materialization_flow() -> None:
        # 1. Setup Stores
        offline_store = DuckDBOfflineStore()
        offline_store.conn.execute("CREATE TABLE high_value_users (entity_id VARCHAR, is_high_value BOOLEAN)")
        offline_store.conn.execute("INSERT INTO high_value_users VALUES ('u1', TRUE), ('u2', FALSE)")

        online_store = InMemoryOnlineStore()
        store = FeatureStore(offline_store=offline_store, online_store=online_store)

        @entity(store)
        class User:
            user_id: str

        # 2. Define SQL Feature for Materialization
        # The SQL query in the definition is what gets executed.
        # It should return [entity_id, value] (aliased as feature name ideally, or just value)
        # The MVP materializer expects the query result to have columns.
        # And it uses `entity_def.id_column` to find the ID.
        # And `feature_name` to find the value.

        @feature(entity=User, sql="SELECT entity_id AS user_id, is_high_value FROM high_value_users", materialize=True)
        def is_high_value(user_id: str) -> bool:
            return False

        # 3. Run Materialization
        # We call the internal method directly for testing
        store._materialize_feature("is_high_value")

        # 4. Verify Online Store
        # Check u1
        features_u1 = await online_store.get_online_features("User", "u1", ["is_high_value"])
>       assert features_u1["is_high_value"] is True
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       KeyError: 'is_high_value'

tests/integration/test_offline_flow.py:92: KeyError
=============================== warnings summary ===============================
tests/integration/test_offline_flow.py::test_materialization_flow
  /Users/davidahmann/Projects/meridian_oss/src/meridian/core.py:233: RuntimeWarning: coroutine 'InMemoryOnlineStore.set_online_features_bulk' was never awaited
    logger.error("materialize_failed", feature=feature_name, error=str(e))
  Enable tracemalloc to get traceback where the object was allocated.
  See https://docs.pytest.org/en/stable/how-to/capture-warnings.html#resource-warnings for more info.

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/integration/test_offline_flow.py::test_hybrid_offline_retrieval
FAILED tests/integration/test_offline_flow.py::test_materialization_flow - Ke...
========================= 2 failed, 1 warning in 0.36s =========================
