Skip to main content

A Pythonic SDK for Malaysia's OpenDOSM and data.gov.my Open API

Project description

opendosm 🇲🇾

CI PyPI Python License: MIT

A Pythonic SDK for Malaysia's data.gov.my Open API — providing clean access to OpenDOSM statistical datasets with optional Pandas integration.

Features

  • 🔍 Fluent QueryBuilder — filter, sort, paginate, and select columns with a chainable API
  • 🗂️ Dataset discoverylist_datasets() and search() to find any of the 280+ available datasets
  • 📊 Pandas integration.to_dataframe() with automatic date parsing
  • Smart retries — automatic exponential backoff on rate limits (429)
  • 🔐 Token auth — optional API token for higher rate limits
  • 🧩 Typed — full type hints and Pydantic response models
  • 📦 Zero config — works out of the box, no API key required

Installation

pip install opendosm

# With Pandas support
pip install opendosm[pandas]

Quick Start

from opendosm import OpenDOSM

client = OpenDOSM()

# Fetch CPI data
cpi_data = client.opendosm.cpi()

# Fetch population data
population = client.opendosm.population()

# Fetch any dataset by ID
data = client.opendosm.get("gdp_qtr_real")

# Don't forget to close
client.close()

Context Manager

with OpenDOSM() as client:
    data = client.opendosm.get("cpi_core")

With API Token

client = OpenDOSM(token="your-api-token")

Filtering & Queries

Use the fluent QueryBuilder to construct queries:

from opendosm import OpenDOSM, QueryBuilder

client = OpenDOSM()

query = (
    QueryBuilder()
    .filter(state="Selangor")
    .date_range("date", start="2023-01-01", end="2023-12-31")
    .sort("date", descending=True)
    .limit(50)
    .include("date", "state", "value")
)

data = client.opendosm.get("cpi_core", query=query)

Available Query Methods

Method Description Example
.filter(**kwargs) Exact match (case-sensitive) .filter(state="Selangor")
.ifilter(**kwargs) Exact match (case-insensitive) .ifilter(state="selangor")
.contains(**kwargs) Partial match (case-sensitive) .contains(name="Kuala")
.icontains(**kwargs) Partial match (case-insensitive) .icontains(name="kuala")
.range(col, begin, end) Numerical range .range("value", 10, 100)
.sort(*cols, descending) Sort results .sort("date", descending=True)
.date_range(col, start, end) Date filter (YYYY-MM-DD) .date_range("date", start="2023-01-01")
.timestamp_range(col, start, end) Timestamp filter (YYYY-MM-DD HH:MM:SS) .timestamp_range("ts", start="2023-01-01 00:00:00")
.limit(n) Max records .limit(100)
.include(*cols) Include columns only .include("date", "value")
.exclude(*cols) Exclude columns .exclude("id")
.with_meta() Include metadata .with_meta()

Note: When both .include() and .exclude() are used, include takes precedence.

Pandas Integration

from opendosm import OpenDOSM

client = OpenDOSM()

# Fetch and convert to DataFrame
data = client.opendosm.cpi()
df = client.to_dataframe(data)

print(df.head())
print(df.dtypes)  # Date columns auto-parsed!

Convenience Methods

The SDK provides shortcuts for popular datasets:

client.opendosm.cpi()          # Consumer Price Index (default: "cpi_core")
client.opendosm.gdp()          # Gross Domestic Product (default: "gdp_qtr_real")
client.opendosm.population()   # Population by State (default: "population_state")
client.opendosm.trade()        # External Trade (default: "trade_sitc_1d")
client.opendosm.labour()       # Labour Force Survey (default: "lfs_month")

All accept an optional query parameter and custom dataset_id.

Data Catalogue API

Access the broader data.gov.my catalogue (280+ datasets):

# Fetch a specific dataset
data = client.data_catalogue.get("fuelprice")

# Discover available datasets (live from API, always up to date)
all_datasets = client.data_catalogue.list_datasets()

# Filter by category or source
demo = client.data_catalogue.list_datasets(category="Demography")
dosm = client.data_catalogue.list_datasets(source="DOSM")

# Search by keyword across IDs and titles
gdp_datasets = client.data_catalogue.search("gdp")
for ds in gdp_datasets:
    print(f"{ds.id}: {ds.title_en}")

Error Handling

from opendosm import OpenDOSM, RateLimitError, NotFoundError

client = OpenDOSM()

try:
    data = client.opendosm.get("nonexistent_dataset")
except NotFoundError:
    print("Dataset not found!")
except RateLimitError:
    print("Rate limited — try again later or use an API token")

Development

# Clone and install in dev mode
git clone https://github.com/aldan-1/opendosm-py.git
cd opendosm-py
pip install -e ".[dev]"

# Run tests
pytest tests/ -v

# Run linter
ruff check src/ tests/

# Type check
mypy src/opendosm/

License

MIT — see LICENSE.

Links

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

opendosm-0.1.0.tar.gz (25.5 kB view details)

Uploaded Source

Built Distribution

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

opendosm-0.1.0-py3-none-any.whl (17.1 kB view details)

Uploaded Python 3

File details

Details for the file opendosm-0.1.0.tar.gz.

File metadata

  • Download URL: opendosm-0.1.0.tar.gz
  • Upload date:
  • Size: 25.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.2

File hashes

Hashes for opendosm-0.1.0.tar.gz
Algorithm Hash digest
SHA256 3d6aebaf95a924cbc99af42339b990af1ad7447ebf8ce7fb142b771a7fe27324
MD5 2ce0dbfab502ad17e43194acd87c065f
BLAKE2b-256 ec6ee8a0dd963e0980648323faea0413845bddabd4a7b0aaae6b030136e3ebc9

See more details on using hashes here.

File details

Details for the file opendosm-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: opendosm-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 17.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.2

File hashes

Hashes for opendosm-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 671a5b174eb6d5cdab73aa70b24848f220589aa5624c44988c93e4ac0c746cf0
MD5 8967697f6ba789ae79332a93562307e9
BLAKE2b-256 63fd50e90a334383f12e2e50bd4068b7291ebe257e3b59a7031a3b00a86e245b

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