Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions .github/workflows/weekly-health.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,24 @@ jobs:
python -m pip install --upgrade pip
pip install -e '.[dev]'

# OILPRICEAPI_TEST_KEY currently resolves empty at runtime (see PR).
# Guard at the shell level so the job passes loudly (::warning::) instead
# of failing or silently skipping every test.
- name: Run integration tests
run: pytest tests/ -m 'integration' -v --timeout=60
run: |
if [ -z "$OILPRICEAPI_KEY" ]; then
echo "::warning::OILPRICEAPI_TEST_KEY secret is empty/unset - live integration tests skipped"
exit 0
fi
pytest tests/ -m 'integration' -v --no-cov --timeout=60

- name: Run contract tests
run: pytest tests/ -m 'contract' -v --timeout=60
run: |
if [ -z "$OILPRICEAPI_KEY" ]; then
echo "::warning::OILPRICEAPI_TEST_KEY secret is empty/unset - contract tests skipped"
exit 0
fi
pytest tests/ -m 'contract' -v --no-cov --timeout=60

- name: Check for dependency vulnerabilities
run: |
Expand Down
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,28 @@ for price in prices:
print(f"{price.commodity}: ${price.value:.2f}")
```

### Beyond Oil — Gas, LNG, Carbon & Fuels

The same client covers EU ETS carbon, European gas (TTF), LNG (JKM), and marine/road/aviation fuels — for maritime compliance (EU ETS / FuelEU Maritime), fleet & logistics fuel costing, LNG and European gas analytics, and CBAM reporting.

```python
# EU ETS carbon allowances (EUAs) — spot price in EUR
eua = client.prices.get("EU_CARBON_EUR")
print(f"EU carbon: €{eua.value:.2f}") # €XX.XX per tonne CO2

# Dutch TTF natural gas — futures curve via slug helpers
# (other slugs: "lng-jkm", "eua-carbon", "uk-carbon", "natural-gas")
ttf = client.futures.latest("ttf-gas")
print(ttf["front_month"]["last_price"]) # front-month, €XX.XX/MWh

# Marine bunker fuels (VLSFO / MGO / IFO380) at a specific port
rotterdam = client.bunker_fuels.port("RTM") # 3-letter port codes: SIN, RTM, FUJ, ...
for fuel in rotterdam["prices"]:
print(f"{fuel['grade']}: ${fuel['price']}/{fuel['unit']}") # VLSFO: $XXX.XX/MT
```

Spot codes for these markets also work with `client.prices.get()` / `get_multiple()`: `DUTCH_TTF_EUR`, `JKM_LNG_USD`, `VLSFO_USD`, `JET_FUEL_USD`, `DIESEL_USD`, `NATURAL_GAS_USD`. (Futures and bunker endpoints require a plan with futures data — spot prices work on every tier.)

### Historical Data with Pandas

```python
Expand Down
17 changes: 13 additions & 4 deletions tests/contract/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,14 @@
import os
import pytest
from pathlib import Path
from dotenv import dotenv_values
try:
from dotenv import dotenv_values
except ImportError:
# python-dotenv is optional (not in the [dev] extra). In CI the API key
# comes from the environment, so don't make the contract suite
# uncollectable when dotenv isn't installed.
def dotenv_values(_path): # type: ignore[misc]
return {}
from oilpriceapi import OilPriceAPI

# Load .env file from project root
Expand All @@ -16,15 +23,17 @@
env_vars = dotenv_values(env_path)

# Get API credentials
API_KEY = env_vars.get('OILPRICEAPI_KEY')
BASE_URL = env_vars.get('OILPRICEAPI_BASE_URL', 'https://api.oilpriceapi.com')
# Prefer .env for local dev, fall back to the environment for CI
# (weekly-health.yml sets OILPRICEAPI_KEY from the OILPRICEAPI_TEST_KEY secret).
API_KEY = env_vars.get('OILPRICEAPI_KEY') or os.environ.get('OILPRICEAPI_KEY')
BASE_URL = env_vars.get('OILPRICEAPI_BASE_URL') or os.environ.get('OILPRICEAPI_BASE_URL', 'https://api.oilpriceapi.com')


@pytest.fixture(scope="session")
def api_key():
"""Provide API key for tests."""
if not API_KEY:
pytest.skip("OILPRICEAPI_KEY not found in .env file")
pytest.skip("OILPRICEAPI_KEY not found in .env file or environment")
return API_KEY


Expand Down
8 changes: 5 additions & 3 deletions tests/integration/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@ def dotenv_values(_path): # type: ignore[misc]
env_vars = dotenv_values(env_path)

# Get API credentials
API_KEY = env_vars.get('OILPRICEAPI_KEY')
BASE_URL = env_vars.get('OILPRICEAPI_BASE_URL', 'https://api.oilpriceapi.com')
# Prefer .env for local dev, fall back to the environment for CI
# (weekly-health.yml sets OILPRICEAPI_KEY from the OILPRICEAPI_TEST_KEY secret).
API_KEY = env_vars.get('OILPRICEAPI_KEY') or os.environ.get('OILPRICEAPI_KEY')
BASE_URL = env_vars.get('OILPRICEAPI_BASE_URL') or os.environ.get('OILPRICEAPI_BASE_URL', 'https://api.oilpriceapi.com')

# CI shares a single 1-request/second API key across repositories, so live
# tests can collide and get HTTP 429 (RateLimitError) through no fault of the
Expand All @@ -52,7 +54,7 @@ def _throttle_live_calls():
def api_key():
"""Provide API key for tests."""
if not API_KEY:
pytest.skip("OILPRICEAPI_KEY not found in .env file")
pytest.skip("OILPRICEAPI_KEY not found in .env file or environment")
return API_KEY


Expand Down
Loading