How to Build a Mock Offline Feature Store in Python

Build an in-memory mock of an offline feature store with a dict-based FeatureStore class for storing and retrieving ML features by entity ID.

Easy Python 3.9+ Aug 9, 2026 ML engineering pipelines 14 views 0 copies

Python code

30 lines
Python 3.9+
from datetime import datetime
from collections import defaultdict


class FeatureStore:
    """Simple in-memory mock of an offline feature store."""

    def __init__(self):
        self._features = defaultdict(dict)

    def ingest(self, entity_id, feature_name, value, timestamp=None):
        ts = timestamp or datetime.utcnow().isoformat()
        self._features[entity_id][feature_name] = {"value": value, "ts": ts}

    def get(self, entity_id, feature_name):
        return self._features.get(entity_id, {}).get(feature_name)

    def get_all(self, entity_id):
        return dict(self._features.get(entity_id, {}))


if __name__ == "__main__":
    store = FeatureStore()
    store.ingest("user_42", "age", 31, "2024-01-15T10:30:00")
    store.ingest("user_42", "city", "Paris", "2024-01-15T11:00:00")
    store.ingest("user_7", "age", 24, "2024-02-01T09:00:00")

    print(store.get("user_42", "age"))
    print(store.get("user_42", "city"))
    print(store.get_all("user_7"))

Output

stdout
{'value': 31, 'ts': '2024-01-15T10:30:00'}
{'value': 'Paris', 'ts': '2024-01-15T11:00:00'}
{'age': {'value': 24, 'ts': '2024-02-01T09:00:00'}}

How it works

The FeatureStore class uses a nested defaultdict(dict) so new entity IDs and feature names auto-create empty dicts on first access. The ingest method stores each feature as a small dict with value and ts keys, defaulting the timestamp to UTC now if none is provided. get safely returns None for missing entities or features using chained .get() calls with empty dict fallbacks. get_all returns a copy of the entity's features to avoid exposing the internal structure. This pattern mimics the read/write interface of production feature stores like Feast or Tecton without external dependencies, making it ideal for local development and unit tests.

Common mistakes

  • Mutating the returned dict from get_all and accidentally changing internal state without using dict() to copy
  • Forgetting that defaultdict will create empty dictionaries on missing key access, which can mask data errors
  • Assuming concurrent access is safe — this mock is not thread-safe for production use

Variations

  1. Use a SQLite in-memory database for SQL query support and schema enforcement
  2. Add a `get_features(entity_id, feature_names)` bulk method to emulate batch retrieval from a warehouse

Real-world use cases

  • Stubbing feature retrieval in unit tests for training pipelines where the full feature store is unavailable.
  • Prototyping a local ML feature engineering workflow before deploying to a cloud feature store.
  • Bundling a lightweight feature cache for batch scoring in a data science notebook or demo script.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from ML engineering pipelines

Related tutorials and quizzes for this topic.