Skip to main content

Python client for FeatureMesh - Execute FeatureQL queries on multiple database backends

Project description

FeatureMesh Python Client

FeatureMesh Python client library for executing FeatureQL queries using various database backends.

Installation

pip install featuremesh

Features

  • Multiple Backend Support: DuckDB, Trino, BigQuery, DataFusion
  • Offline & Online Modes: Execute queries on SQL backends or FeatureMesh serving
  • Python Integration: Query results returned as DataFrames
  • Jupyter Magic Commands: Execute queries directly in notebooks

Quick Start

Get your access token

Get your identity token on https://console.featuremesh.com/login (page settings) and generate an access token for your project.

from featuremesh import generate_access_token

__YOUR_IDENTITY_TOKEN__ = "your_identity_token"
__YOUR_ACCESS_TOKEN__ = generate_access_token(identity_token=__YOUR_IDENTITY_TOKEN__, project='hello_org/hello_project')

To help you make sense of your token, you can decode it:

from featuremesh import decode_token

decoded_token = decode_token(access_token=__YOUR_ACCESS_TOKEN__)
print(decoded_token)

Offline Client (Local SQL Execution)

Execute FeatureQL queries via local SQL backends like DuckDB:

from featuremesh import OfflineClient, Backend
import duckdb

# Create a SQL executor function for DuckDB
def query_duckdb(sql: str):
    """Execute SQL query and return results as DataFrame."""
    conn = duckdb.connect(":memory:")
    result = conn.sql(sql)
    return result.df()

# Create an offline client
client = OfflineClient(
    access_token=__YOUR_ACCESS_TOKEN__,
    backend=Backend.DUCKDB,
    sql_executor=query_duckdb
)

# Execute a FeatureQL query
result = client.query("""
    WITH 
        FEATURE1 := INPUT(BIGINT) 
    SELECT 
        FEATURE1 := BIND_TABLE(ARRAY[1, 2, 3]),
        FEATURE2 := FEATURE1 * 2
""")

# Access results
print(result.dataframe)  # Pandas DataFrame
print(result.sql)        # Translated SQL
print(result.success)    # True if query succeeded

Online Client (API Execution)

Execute FeatureQL queries via the FeatureMesh serving API:

from featuremesh import OnlineClient

# Create an online client
client = OnlineClient(access_token=__YOUR_ACCESS_TOKEN__)

# Execute a FeatureQL query
result = client.query("""
    WITH 
        FEATURE1 := INPUT(BIGINT) 
    SELECT 
        FEATURE1 := BIND_TABLE(ARRAY[1, 2, 3]),
        FEATURE2 := FEATURE1 * 2
""")

# Access results
print(result.dataframe)

Translation Only

Translate FeatureQL to SQL without executing:

# Only available with OfflineClient
featureql_query = """
    WITH 
        FEATURE1 := INPUT(BIGINT) 
    SELECT 
        FEATURE1 := BIND_TABLE(ARRAY[1, 2, 3]),
        FEATURE2 := FEATURE1 * 2
"""
translate_result = client.translate(featureql_query)

print(translate_result.sql)      # Generated SQL
print(translate_result.success)  # True if translation succeeded

Jupyter Notebook Integration

Load the FeatureMesh magic extension in Jupyter:

%load_ext featuremesh

Set a default client:

from featuremesh import set_default, OfflineClient, Backend
import duckdb

# Create SQL executor
def query_duckdb(sql: str):
    return duckdb.sql(sql).df()

# Create and set default client
client = OfflineClient(
    access_token=__YOUR_ACCESS_TOKEN__,
    backend=Backend.DUCKDB,
    sql_executor=query_duckdb
)

set_default("client", client)

Execute queries using the %%featureql cell magic:

%%featureql

WITH 
    FEATURE1 := INPUT(BIGINT) 
SELECT 
    FEATURE1 := BIND_TABLE(ARRAY[1, 2, 3]),
    FEATURE2 := FEATURE1 * 2
FEATURE1 FEATURE2
1 2
2 4
3 6

Available Magic Options

  • --client CLIENT: Use a specific client variable from the notebook namespace
  • --debug: Enable debug mode for detailed query information
  • --show-sql: Print the translated SQL query
  • --hide-dataframe: Hide the DataFrame output
  • --show-slt: Print the SLT (SQL Logic Test) format
  • --hook VARIABLE: Store complete results as a dictionary in a variable

Example:

%%featureql --client client_duckdb --show-sql --hook results

WITH 
    FEATURE1 := INPUT(BIGINT) 
SELECT 
    FEATURE1 := BIND_TABLE(ARRAY[1, 2, 3]),
    FEATURE2 := FEATURE1 * 2

Configuration

Configure default settings using set_default():

from featuremesh import set_default

# API endpoints
set_default("registry.host", "https://api.featuremesh.com")
set_default("registry.path", "/v1/featureql")
set_default("registry.timeout", 30)

# Display preferences
set_default("debug_mode", False)
set_default("show_sql", True)

# Get current settings
from featuremesh import get_default, get_all_defaults

debug_mode = get_default("debug_mode")
all_settings = get_all_defaults()

Supported Backends

DuckDB

from featuremesh import OfflineClient, Backend
import duckdb

# Option 1: Using a persistent connection
_duckdb_conn = None

def get_duckdb_conn(storage_path: str = ":memory:"):
    """Get or create a DuckDB connection."""
    global _duckdb_conn
    if _duckdb_conn is None:
        _duckdb_conn = duckdb.connect(storage_path)
    return _duckdb_conn

def query_duckdb(sql: str, storage_path: str = ":memory:"):
    """Execute SQL query and return results as DataFrame."""
    conn = get_duckdb_conn(storage_path)
    result = conn.sql(sql)
    return result.df()

client = OfflineClient(
    access_token=__YOUR_ACCESS_TOKEN__,
    backend=Backend.DUCKDB,
    sql_executor=query_duckdb
)

# Option 2: Simple in-memory executor
def simple_duckdb_executor(sql: str):
    return duckdb.sql(sql).df()

client = OfflineClient(
    access_token=__YOUR_ACCESS_TOKEN__,
    backend=Backend.DUCKDB,
    sql_executor=simple_duckdb_executor
)

Trino

from featuremesh import OfflineClient, Backend
import pandas as pd
import trino.dbapi

def query_trino(sql: str):
    """Execute SQL query on Trino and return results as DataFrame."""
    # Configure your Trino connection details
    conn = trino.dbapi.connect(
        host="localhost",  # or host.docker.internal for docker
        port=8080,
        user="admin",
        catalog="memory",
        schema="default"
    )
    cur = conn.cursor()
    cur.execute(sql)
    
    # Fetch results
    cols = cur.description
    rows = cur.fetchall()
    
    if len(rows) > 0:
        df = pd.DataFrame(rows, columns=[col[0] for col in cols])
        return df
    else:
        return pd.DataFrame()

client = OfflineClient(
    access_token=__YOUR_ACCESS_TOKEN__,
    backend=Backend.TRINO,
    sql_executor=query_trino
)

# For production with OAuth2 authentication:
import trino.auth

def query_trino_oauth(sql: str):
    """Execute SQL query on Trino with OAuth2 authentication."""
    conn = trino.dbapi.connect(
        host="trino.your-domain.com",
        port=443,
        user="your-username",
        catalog="your-catalog",
        schema="default",
        http_scheme="https",
        auth=trino.auth.OAuth2Authentication()
    )
    cur = conn.cursor()
    cur.execute(sql)
    cols = cur.description
    rows = cur.fetchall()
    
    if len(rows) > 0:
        return pd.DataFrame(rows, columns=[col[0] for col in cols])
    return pd.DataFrame()

BigQuery

from featuremesh import OfflineClient, Backend
from google.cloud import bigquery

def query_bigquery(sql: str):
    """Execute SQL query on BigQuery and return results as DataFrame."""
    client = bigquery.Client(project=__YOUR_PROJECT_ID__)
    return client.query(sql).to_dataframe()

client = OfflineClient(
    access_token=__YOUR_ACCESS_TOKEN__,
    backend=Backend.BIGQUERY,
    sql_executor=query_bigquery
)

Error Handling

All operations return result objects with error information:

result = client.query("""
    WITH 
        FEATURE1 := INPUT(BIGINT) 
    SELECT 
        FEATURE1 := BIND_TABLE(ARRAY[1, 2, 3]),
        FEATURE2 := FEATURE1 * 2
""")

if result.success:
    print("Query succeeded!")
    print(result.dataframe)
else:
    print("Query failed!")
    for error in result.errors:
        print(f"Error [{error.code}]: {error.message}")
        if error.context:
            print(f"Context: {error.context}")

Display utilities are also available:

from featuremesh import display_errors, display_warnings

display_errors(result.errors)
display_warnings(result.warnings)

Debug Mode

Enable debug mode to see detailed translation information:

result = client.query("""
    WITH 
        FEATURE1 := INPUT(BIGINT) 
    SELECT 
        FEATURE1 := BIND_TABLE(ARRAY[1, 2, 3]),
        FEATURE2 := FEATURE1 * 2
""", debug_mode=True)

if result.debug_logs:
    print(result.debug_logs)

Result Objects

QueryResult

Returned by client.query():

@dataclass
class QueryResult:
    featureql: str                    # Original FeatureQL query
    sql: Optional[str]                # Translated SQL
    dataframe: Optional[pd.DataFrame] # Query results
    slt: Optional[str]                # SLT format (offline only)
    warnings: list[Warning]           # Non-blocking warnings
    errors: list[Error]               # Errors that occurred
    backend: Optional[str]            # Backend used
    debug_mode: bool                  # Debug mode enabled
    debug_logs: Optional[dict]        # Debug information
    client_type: str                  # "OfflineClient" or "OnlineClient"
    success: bool                     # Property: True if no errors

TranslateResult

Returned by client.translate() (OfflineClient only):

@dataclass
class TranslateResult:
    featureql: str                  # Original FeatureQL query
    sql: Optional[str]              # Translated SQL
    warnings: list[Warning]         # Non-blocking warnings
    errors: list[Error]             # Errors that occurred
    full_response: Optional[dict]   # Full API response
    backend: Optional[str]          # Backend used
    debug_mode: bool                # Debug mode enabled
    debug_logs: Optional[dict]      # Debug information
    client_type: str                # "OfflineClient"
    success: bool                   # Property: True if no errors

License

MIT License

Support

For issues, questions, or contributions, please visit:

Version

Current version: See featuremesh.__version__

import featuremesh
print(featuremesh.__version__)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

featuremesh-0.1.1.tar.gz (26.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

featuremesh-0.1.1-py3-none-any.whl (26.1 kB view details)

Uploaded Python 3

File details

Details for the file featuremesh-0.1.1.tar.gz.

File metadata

  • Download URL: featuremesh-0.1.1.tar.gz
  • Upload date:
  • Size: 26.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.4

File hashes

Hashes for featuremesh-0.1.1.tar.gz
Algorithm Hash digest
SHA256 4e8a90031ff8596fcd99cf44e89a6bf16b7e35d5efb6a4492a7af2c5c3b32136
MD5 8932c6ab056ba6ca6f3ef60188753c8f
BLAKE2b-256 d40bded41de7150616290b7cea48e74376d0377a087ae43d6b457efae0a2559e

See more details on using hashes here.

File details

Details for the file featuremesh-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: featuremesh-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 26.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.4

File hashes

Hashes for featuremesh-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 29dd084c78832e493f898f7619f72732ea78fad731c419e1e5c5e10b71c6d4e7
MD5 b5db941666a546f4150d7ba039d86236
BLAKE2b-256 081f78e29c0606395a5fdafd1e2b09ec6dc328ea4cc6470c0188458b332a3154

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page