xo-core Package¶
xo-core v1.6.0 -- The foundation package of the XO-Data platform. Provides core utilities, data extractors, and managers for common data engineering operations.
Purpose¶
xo-core serves as the shared utility layer for all XO-Data packages and applications. It contains:
- Extractors: API data source connectors (Gladly, Sprout Social, Medallia/Stella Connect). Gmail, Google Sheets/Drive, and S3 are accessed via the service managers below (wrapped by foundry extract tasks), not via extractor classes.
- Managers: Service wrappers (Snowflake, S3, Google Services)
- Utilities: DataFrame operations, file handling, logging
Installation¶
# Install xo-core package
uv sync --package xo-core
# Add as dependency to another package
uv add --package xo-foundry xo-core
Package Structure¶
packages/xo-core/src/xo_core/
├── extractors/ # API data source connectors
│ ├── gladly_extractor.py # GladlyAPIClient
│ ├── sprout_extractor.py # SproutAPIClient
│ └── medallia_extractor.py # MedalliaAPIClient (Stella Connect CSAT)
│ # Gmail / GSheets / Drive / S3 use the
│ # managers below, not extractor classes
│
├── google_services/ # Google API integrations
│ ├── auth.py # OAuth2 authentication
│ ├── gmail_manager.py # Gmail operations
│ ├── gdrive_manager.py # Google Drive operations
│ └── gsheets_manager.py # Google Sheets operations (gspread)
│
├── snowflake_manager.py # Snowflake operations (SnowflakeManager)
├── s3_manager.py # S3 operations (S3Manager)
├── df_utils.py # DataFrame cleaning / standardization
├── file_utils.py # File handling
├── logger.py # Logging configuration
└── __init__.py
Key Components¶
Extractors¶
Data source connectors that extract data and upload to S3.
No pandas in extraction
xo-foundry extraction tasks (which wrap these extractors) use native Python csv.DictWriter -- never pandas. Pandas corrupts data via automatic type inference (IDs become floats, leading zeros stripped). Let Snowflake handle type conversion.
GladlyAPIClient¶
Extract reports from the Gladly API.
from xo_core.extractors.gladly_extractor import (
GladlyAPIClient,
extract_gladly_reports,
)
client = GladlyAPIClient(
base_url="https://your-org.gladly.com",
email="user@example.com",
token="your-token",
)
# Methods: get_report(), get_report_by_month(), get_agents()
report_data = client.get_report(...)
SproutAPIClient¶
Extract data from the Sprout Social API.
from xo_core.extractors.sprout_extractor import SproutAPIClient
client = SproutAPIClient(
api_key="your-api-key",
client_id="2105997",
)
# Methods: get_messages(), get_all_messages(), get_cases(), get_profile_analytics()
messages = client.get_messages(...)
MedalliaAPIClient¶
Extract CSAT survey responses from the Medallia (Stella Connect) API.
from xo_core.extractors.medallia_extractor import MedalliaAPIClient
with MedalliaAPIClient(
api_key="your-api-key",
token="your-token"
) as client:
responses = client.get_csat_responses(
responded_at_gte="2026-01-15",
responded_at_lte="2026-01-15"
)
Authentication: Header-based (x-api-key + Authorization token).
Retry logic: 3 attempts with exponential backoff on 429 rate-limit responses.
Returns: list[dict[str, Any]] — raw API response records, one per CSAT survey response.
Gmail, Google Sheets & S3 — use managers, not extractors¶
There are no GmailExtractor, GSheetsExtractor, or S3Extractor classes. These sources are accessed through service managers — GmailManager and GSheetsManager (and GDriveManager) under google_services/, and S3Manager — which the foundry extract tasks (extract_gmail_data, extract_gsheet_data, etc.) wrap. Foundry exposes these as gmail, gsheet, and s3 source types.
Managers¶
Service wrappers that provide high-level operations for external services.
SnowflakeManager¶
Modern Snowflake connector with DataFrame operations and deduplication.
from xo_core.snowflake_manager import SnowflakeManager
manager = SnowflakeManager()
# Upload DataFrame with deduplication
prepped_df = manager.prep_dataframe_for_table(
df=raw_df,
table_name="GLADLY_CONTACT_TIMESTAMPS",
filter_existing=True
)
manager.upload_dataframe(
prepped_df,
table_name="GLADLY_CONTACT_TIMESTAMPS",
database="WBP_DB",
schema="BRONZE"
)
# Execute query
results = manager.execute_query("SELECT COUNT(*) FROM TABLE")
# Download table to DataFrame
df = manager.download_table("DATABASE.SCHEMA.TABLE")
Key Features:
- Automatic deduplication (single-field or multi-field)
- Type-safe DataFrame uploads
- Connection pooling
- Prepared statement support
S3Manager¶
S3 operations with DataFrame support.
from xo_core.s3_manager import S3Manager
manager = S3Manager()
# Upload DataFrame
manager.upload_dataframe(
df,
bucket="xo-ingest",
key="client/report/2026-01-15/data.csv"
)
# Download to DataFrame
df = manager.download_to_dataframe(
bucket="xo-ingest",
key="client/report/2026-01-15/data.csv"
)
# List files
files = manager.list_files(bucket="xo-ingest", prefix="client/")
Google Services¶
GSheetsManager¶
Google Sheets operations via gspread library.
from xo_core.google_services.gsheets_manager import GSheetsManager
gsheets = GSheetsManager(credentials_path="credentials.json")
# Read spreadsheet
data = gsheets.read_sheet(spreadsheet_id="abc123", sheet_name="Data")
GmailManager¶
Gmail API operations.
from xo_core.google_services.gmail_manager import GmailManager
gmail = GmailManager(credentials_path="credentials.json")
# List messages
messages = gmail.list_messages(label="Reports", after_date="2026-01-15")
# Get attachments
attachments = gmail.get_attachments(message_id="abc123")
Utilities¶
df_utils¶
DataFrame cleaning and standardization utilities.
from xo_core.df_utils import (
clean_column_names,
clean_dataframe,
datetime_columns_handler,
convert_to_nullable_int_columns,
generate_record_key
)
# Clean column names (UPPERCASE, replace special chars)
df.columns = clean_column_names(df.columns)
# Comprehensive DataFrame cleaning
df = clean_dataframe(
df,
uppercase_columns=True,
datetime_columns=['CREATED_AT'],
auto_detect_int_columns=True,
replace_empty_strings=True
)
Key Functions:
| Function | Purpose |
|---|---|
clean_column_names() |
Standardize column names (UPPERCASE, _) |
clean_dataframe() |
All-in-one DataFrame cleaning |
datetime_columns_handler() |
Convert to datetime with timezone |
convert_to_nullable_int_columns() |
Convert to Int64 (allows nulls) |
replace_empty_strings_with_na() |
Replace "" with NA |
drop_empty_columns() |
Remove columns with all nulls |
generate_record_key() |
Generate unique keys for deduplication |
logger¶
Consistent logging configuration.
from xo_core.logger import get_module_logger
logger = get_module_logger(__name__)
logger.info("Processing started")
logger.warning("Missing optional field")
logger.error("Failed to connect", exc_info=True)
Type Safety¶
xo-core is fully typed and must pass ty with zero errors:
from typing import Any
import pandas as pd
def process_data(items: list[dict[str, str]]) -> pd.DataFrame:
"""Process data with proper typing."""
...
Testing¶
# Run xo-core tests
uv run pytest packages/xo-core/tests/
# Run specific test file
uv run pytest packages/xo-core/tests/test_df_utils.py
# Run with coverage
uv run pytest --cov=xo_core packages/xo-core/tests/
Dependencies¶
Key dependencies:
pandas>=2.0-- DataFrame operationssnowflake-connector-python-- Snowflake connectivityboto3-- AWS S3 operationsgoogle-auth-- Google API authenticationgspread-- Google Sheets APIrequests-- HTTP client for APIstqdm-- Progress bars
Next Steps¶
- xo-foundry Package -- Orchestration layer
- ELT Pipeline Flow -- Pipeline architecture
- Naming Conventions -- Standards
Package Location: packages/xo-core/
Version: 1.6.0
Dependencies: See packages/xo-core/pyproject.toml