A Python package for working with Quantec EasyData.
Project description
Quantec
A Python package for working with Quantec EasyData API. Fetch economic time series data with support for caching and advanced filtering.
⚠️ Early Development Notice: This package is in early development and may undergo breaking changes without backwards compatibility until version 1.0 is reached.
The Quantec EasyData API is available to EasyData subscribers. To subscribe and get API access, visit quantec.co.za/easydata for more information.
Features
- 🎯 Multiple Data Access: Time series codes, selections, and grid/pivot data
- 📊 Format Support: CSV for time series, CSV/Parquet for grid data
- 📈 Multiple Frequencies: Monthly (M), Quarterly (Q), and Annual (A) frequencies
- 🔍 Advanced Filtering: Dimension-based filtering for grid data
- ⚡ Performance Caching: Optional caching for time series and grid data
- 🛡️ Error Handling: Comprehensive network and API error handling
- 🔧 Flexible Configuration: Environment variables and parameter setup
- 🔐 Header Authentication: API keys are sent via the
Authorizationheader only
Installation
pip install quantec
Quick Start
from quantec.easydata.client import Client
# Initialize client
client = Client()
# Get time series data (CSV format only)
data = client.get_data(time_series_codes="NMS-EC_BUS,NMS-GA_BUS")
print(data.head())
Configuration
Environment Variables
Mac/Linux (bash/zsh):
export EASYDATA_API_KEY="your-api-key-here"
export EASYDATA_API_URL="https://www.easydata.co.za/api/v3/"
On Windows (PowerShell):
$env:EASYDATA_API_KEY = "your-api-key-here"
$env:EASYDATA_API_URL = "https://www.easydata.co.za/api/v3/"
Authentication
Quantec uses header-only API authentication. Provide your API key via api_key or
EASYDATA_API_KEY; the client sends it as an Authorization: Token ... header.
API keys are never added to query parameters.
The client also sends a default User-Agent of quantec-python/<version>. Apps can
identify themselves by passing a product prefix:
client = Client(user_agent="easydata-cli/0.3.0")
# Sends: User-Agent: easydata-cli/0.3.0 quantec-python/<version>
Client Options
from quantec.easydata.client import Client
# Basic client (uses environment variables)
client = Client()
# All parameters and defaults
client = Client(
api_key=None, # default: uses EASYDATA_API_KEY env var
api_url=None, # default: EASYDATA_API_URL or "https://www.easydata.co.za/api/v3"
use_cache=True,
cache_dir="cache",
user_agent=None, # optional product identifier, e.g. "easydata-cli/0.3.0"
headers=None, # optional additional default request headers
)
Time Series Data
Main Methods
-
get_data: Fetch time series or selection data.
- Parameters:
time_series_codes: Optional[str] = None- Comma-separated time series codesselection_pk: Optional[int] = None- Selection primary key (takes precedence over codes)freq: str = "A"- Data frequency ("M", "Q", "A")start_year: str = ""- Start year (yyyy)end_year: str = ""- End year (yyyy)analysis: bool = False- Include analysis (selection_pk only)resp_format: str = "dataframe"- Response format ("dataframe", "csv", "json")is_tidy: bool = True- Return tidy data
- Returns: DataFrame when
resp_format="dataframe", CSV string when"csv", dict when"json".
- Parameters:
-
get_selections: Fetch user selections.
- Parameters:
status: Optional[str] = None- Status flags: U=Unsaved, P=Private, S=Shared, O=Open, W=Owner (e.g., "PSW" for Private and Shared selections owned by user)show: Optional[str] = None- Selection visibility filter passed through to the APIfilter: Optional[str] = None- Selection state filter passed through to the API
- Returns: DataFrame of selections.
- Parameters:
Direct Access with Codes
# Single time series
data = client.get_data(time_series_codes="NMS-EC_BUS")
# Multiple time series
data = client.get_data(time_series_codes="NMS-EC_BUS,NMS-GA_BUS")
# With date filtering and frequency
data = client.get_data(
time_series_codes="NMS-EC_BUS,NMS-GA_BUS",
freq="Q", # Quarterly data
start_year="2020", # Year format only
end_year="2023"
)
# Different return formats
df_data = client.get_data(time_series_codes="NMS-EC_BUS", resp_format="dataframe") # Default
csv_data = client.get_data(time_series_codes="NMS-EC_BUS", resp_format="csv") # Raw CSV string
json_data = client.get_data(time_series_codes="NMS-EC_BUS", resp_format="json") # JSON dict
Discovery-Based Access
# Find available selections
selections = client.get_selections(status="PSO") # Private, Shared, Open
# Or get only private and shared selections owned by user
selections = client.get_selections(status="PSW") # Private, Shared, Owner
# Use selection for data retrieval (returns DataFrame)
if len(selections) > 0:
selection_pk = selections.iloc[0]['pk']
data = client.get_data(selection_pk=selection_pk)
Grid/Pivot Data
Main Methods
-
get_recipes: Fetch available recipes.
- Parameters: none.
- Returns: DataFrame of recipes.
-
get_grid_data: Fetch grid/pivot data by recipe.
- Parameters:
recipe_pk: int- Recipe primary key identifieris_expanded: bool = False- Return expanded data formatis_melted: bool = True- Return melted data formatresp_format: str = "dataframe"- Response format ("dataframe", "csv", "parquet")selectdimensionnodes: dict | list[dict] | None = None- Dimension filteringhas_tscodes: bool = False- Include time series codeshas_dncodes: bool = False- Include dimension node codesis_sparse: bool = True- Return sparse data formatfreq: Optional[str] = None- Data frequency ("M", "Q", "A")
- Returns: DataFrame when
resp_format="dataframe", CSV string when"csv", bytes when"parquet".
- Parameters:
Basic Grid Data Access
# Get available recipes
recipes = client.get_recipes()
# Basic grid data retrieval
if len(recipes) > 0:
recipe_id = recipes.iloc[0]['id']
grid_data = client.get_grid_data(recipe_pk=recipe_id)
# Grid data with frequency
if len(recipes) > 0:
recipe_id = recipes.iloc[0]['id']
grid_data = client.get_grid_data(
recipe_pk=recipe_id,
freq="Q" # Quarterly data
)
Grid Data with Filtering
# Single dimension filter by levels only
filters = {"dimension": "d3", "levels": [2]}
grid_data = client.get_grid_data(recipe_pk=1066, selectdimensionnodes=filters)
# Single dimension filter by codes only
filters = {"dimension": "d3", "codes": ["TRD01-R_FI"]}
grid_data = client.get_grid_data(recipe_pk=1066, selectdimensionnodes=filters)
# Single dimension filter combining codes and levels
filters = {"dimension": "d3", "levels": [1], "codes": ["TRD01-R_FI"]}
grid_data = client.get_grid_data(recipe_pk=1066, selectdimensionnodes=filters)
# Multiple dimension filters
filters = [
{"dimension": "d1", "codes": ["CODE1", "CODE2"]},
{"dimension": "d3", "levels": [2]},
{"dimension": "d2", "codes": ["PARENT_CODE"], "children": True}
]
grid_data = client.get_grid_data(recipe_pk=1066, selectdimensionnodes=filters)
# Single code with children
filters = {"dimension": "d3", "codes": ["TRD01-R_FI"], "children": True}
grid_data = client.get_grid_data(recipe_pk=1066, selectdimensionnodes=filters)
# Single code with children including self
filters = {"dimension": "d3", "codes": ["TRD01-R_FI"], "children_include_self": True}
grid_data = client.get_grid_data(recipe_pk=1066, selectdimensionnodes=filters)
Supported Filter Combinations
These are the valid filter combinations for each dimension:
- Codes only:
{"dimension": "d1", "codes": ["CODE1", "CODE2", ...]} - Levels only:
{"dimension": "d1", "levels": [1, 2, ...]} - Codes and levels:
{"dimension": "d1", "codes": ["CODE1"], "levels": [1, 2]} - Single code with children:
{"dimension": "d1", "codes": ["PARENT_CODE"], "children": True} - Single code with children including self:
{"dimension": "d1", "codes": ["PARENT_CODE"], "children_include_self": True}
Important constraints:
childrenandchildren_include_selfrequire exactly one codechildrenandchildren_include_selfcannot be used togetherchildrenandchildren_include_selfcannot be combined withlevels- Valid dimensions: "d1", "d2", "d3", "d4", "d5", "d6", "d7"
Format Options (CSV/Parquet only)
# DataFrame format (default)
df_data = client.get_grid_data(recipe_pk=1066)
# CSV format
csv_data = client.get_grid_data(recipe_pk=1066, resp_format="csv")
# Parquet format (recommended for large datasets)
parquet_data = client.get_grid_data(recipe_pk=1066, resp_format="parquet")
Caching
Caching is enabled by default to improve performance. The client automatically caches time series and grid data responses.
# Caching is enabled by default
client = Client() # use_cache=True by default
# Time series caching
ts1 = client.get_data(time_series_codes="NMS-EC_BUS") # fetch + cache
ts2 = client.get_data(time_series_codes="NMS-EC_BUS") # loaded from cache
# Grid data caching
grid1 = client.get_grid_data(recipe_pk=1066) # fetch + cache
grid2 = client.get_grid_data(recipe_pk=1066) # loaded from cache
# Clear cache
client.cache.clear() # Remove all cached files
# Disable caching if needed
no_cache_client = Client(use_cache=False)
Error Handling
import requests
from quantec.easydata.client import Client
client = Client()
try:
data = client.get_data(time_series_codes="INVALID_CODE")
except requests.HTTPError as e:
print(f"API Error: {e}")
except ValueError as e:
print(f"Parameter Error: {e}")
Complete Example
from quantec.easydata.client import Client
# Initialize client with caching
client = Client(use_cache=True, cache_dir="./cache")
# 1. Get time series data
ts_data = client.get_data(
time_series_codes="NMS-EC_BUS,NMS-GA_BUS",
freq="Q",
start_year="2020"
)
# 2. Get selections for discovery
selections = client.get_selections(status="PSO") # Private, Shared, Open
# selections.head()
selection_pk = int(selections.loc[selections.title == "CPI overview", "pk"].iloc[0])
selection_data = client.get_data(
selection_pk=selection_pk,
freq="M"
)
# 3. Get available recipes and grid data for `TRD01` data set
recipes = client.get_recipes()
# recipes.head()
recipe_pk = int(recipes.loc[recipes.dataset_code == "TRD01", "id"].iloc[0])
grid_data = client.get_grid_data(
recipe_pk=recipes.iloc[0]['id'],
)
Important Notes
- Time series data: Supports DataFrame (default), CSV and JSON formats
- Grid data: Supports DataFrame (default), CSV and Parquet formats
- Date parameters: Use year format only (e.g., "2020", not "2020-01-01")
- Caching: Available for time series and grid data by default
- Dimension filtering: Must provide at least one of: codes, levels, children, or children_include_self. May provide a list of filters.
- Authentication: API keys are sent in the
Authorizationheader only, never as query parameters.
License
MIT License - see the LICENSE file for details.
Support
For support, contact Quantec
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file quantec-0.5.1.tar.gz.
File metadata
- Download URL: quantec-0.5.1.tar.gz
- Upload date:
- Size: 87.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.15 {"installer":{"name":"uv","version":"0.11.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5b500bdac542dc42d1e99c072afd8a5df052a50f2f5e1ad4b2875fa6a6557051
|
|
| MD5 |
2931625ca327ae359dae52ab64d21b68
|
|
| BLAKE2b-256 |
aec4361dba79f39d63040362ef355b120cb7e95d1b9138ef7ce5f28d95c50eb4
|
File details
Details for the file quantec-0.5.1-py3-none-any.whl.
File metadata
- Download URL: quantec-0.5.1-py3-none-any.whl
- Upload date:
- Size: 17.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.15 {"installer":{"name":"uv","version":"0.11.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
62bf3b26c3a8b0cc816f3a7c4ff01ae3c973ad5e42b43e59b5af437e9a9aa120
|
|
| MD5 |
ee3b827a9b2a070e868a62777f433612
|
|
| BLAKE2b-256 |
ef934dfe4b1000e61bf2c502347723b171b1d7cc8599d49426d5646efbf96ea0
|