Skip to main content

Temporalis

Unified weather abstraction library for Python. Query multiple weather services through one consistent API, with automatic field derivation, marine forecasts, and an ensemble mode that merges all free sources in parallel.

Why another weather library?

Most Python weather packages are thin wrappers around a single API. Switch providers and you rewrite your whole application. Temporalis solves a different problem: make the provider an implementation detail.

Every provider — whether it's a global model, a national government API, or a free open-data feed — returns the same objects: WeatherData, DataPoint, HourlyForecast, DailyForecast. Your code never touches raw JSON.

The data model earns its keep

DataPoint is not a float. A temperature reading has a value, but it also has a unit, a min, a max, a probability, and a timestamp. A wind speed has a unit that differs between providers. DataPoint captures all of that in one object that serialises cleanly and degrades gracefully when a provider doesn't supply a field:

temp = wx.weather.temperature
print(temp.value, temp.units)       # 18.5 ºC
print(temp.min_val, temp.max_val)   # daily range, if the provider supplies it

Missing fields are filled automatically. When a provider doesn't return dew point, apparent temperature, snow, or UV index, Temporalis derives them from whatever data is available using standard meteorological formulas:

wx = MetNo(lat, lon)
print(wx.weather.dewPoint)          # derived via August-Roche-Magnus
print(wx.weather.uvIndex)           # derived from solar position + cloud cover
print(wx.weather.snow)              # derived when T ≤ 2°C and precipitation > 0

Sun and moon are first-class, not bolted on. Every provider exposes dawn, dusk, sunrise, sunset, noon, moon_phase, and moon_phase_name with no extra API call — computed from coordinates via astral.

Swap providers without changing your code:

# works identically for OWM, OpenMeteo, MetNo, IPMA, NWS, Ensemble
for day in wx.days:
    print(day.weekday, day.temperature, day.precipitation)

Install

pip install temporalis

Providers

Provider Coverage API key Notes
Ensemble Global None (OWM optional) Merges all applicable sources in parallel
OpenMeteo Global None Forecast + historical archive
MetNo Global None Norwegian Met Institute
OWM Global Required OpenWeatherMap; default key bundled
NWS USA only None Raises ValueError outside US
IPMA Portugal only None Raises ValueError outside PT
OpenMeteoMarine Ocean None Wave, swell, current; raises ValueError for landlocked coords
OpenMeteoAirQuality Global None PM2.5, ozone, pollen, NO₂

Quick Start

Single provider

from temporalis.providers.openmeteo import OpenMeteo

lat, lon = 38.7223, -9.1393   # Lisbon
wx = OpenMeteo(lat, lon)

print(wx.weather.summary)
print(wx.weather.temperature)        # DataPoint: value + units
print(wx.weather.dewPoint)           # derived if provider doesn't supply it

for day in wx.days:
    print(day.weekday, day.datetime.date(), day.temperature)

for hour in wx.hours:
    print(hour.datetime.time(), hour.temperature, hour.precipitation)

# Sun times (astral, timezone-aware)
print(wx.dawn, wx.sunrise, wx.noon, wx.sunset, wx.dusk)

# Moon
print(wx.moon_symbol, wx.moon_phase_name)

Ensemble — best data from all free sources

from temporalis.providers.ensemble import Ensemble

wx = Ensemble(lat, lon, units="metric")

print(wx.providers)          # ['openmeteo', 'metno', 'ipma', 'openmeteo_marine', ...]

w = wx.weather
print(w.temperature)         # mean across all providers
# min_val / max_val reflect inter-provider spread — wide = low confidence
print(w.temperature.min_val, w.temperature.max_val)

print(w.waveHeight)          # from OpenMeteoMarine when coastal

Historical data

from temporalis.providers.openmeteo import OpenMeteo
import pendulum

wx = OpenMeteo(lat, lon,
               start=pendulum.date(2024, 1, 1),
               end=pendulum.date(2024, 1, 31))
for day in wx.days:
    print(day.datetime.date(), day.temperature)

Marine forecast

from temporalis.providers.openmeteo_marine import OpenMeteoMarine

wx = OpenMeteoMarine(38.7, -9.5)   # must be over ocean
w = wx.weather
print(w.waveHeight, w.swellHeight, w.wavePeriod)
print(w.currentVelocity, w.currentDirection)

Provider registry

import temporalis.providers.registry   # auto-registers all built-ins
from temporalis.providers import WeatherProvider

print(WeatherProvider.available())
# ['ensemble', 'ipma', 'metno', 'nws', 'openmeteo', 'openmeteo_airquality',
#  'openmeteo_marine', 'owm']

wx = WeatherProvider.get("metno", lat, lon)
wx = WeatherProvider.from_address("Paris, France", name="openmeteo")

Geocode from address

wx = OpenMeteo.from_address("Berlin, Germany")
wx = Ensemble.from_address("Oslo, Norway")

Units

Pass units="metric" (default) or units="us" to any provider constructor. Each provider converts locally — API-native units are never exposed raw.

wx_us = OpenMeteo(lat, lon, units="us")
print(wx_us.weather.temperature)   # ºF
print(wx_us.weather.windSpeed)     # mph

Caching

Each provider instance owns its own requests.Session. To add caching, wrap the session after construction:

import requests_cache
wx = OpenMeteo(lat, lon)
wx.session = requests_cache.CachedSession("weather_cache", expire_after=600)

Derived fields

Fields filled automatically when the provider doesn't supply them:

Field Formula Inputs
dewPoint August-Roche-Magnus temp + humidity
apparentTemperature Wind chill (T<10°C) or heat index (T>27°C) temp + wind or humidity
snow precipitation when T ≤ 2°C temp + precipitation
uvIndex NOAA solar position + Josefsson cloud attenuation lat/lon + datetime + cloud cover

See docs/derived-fields.md for formulas, validity ranges, and accuracy limits.

License

Apache 2.0

Metadata

Release files for temporalis 0.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for temporalis 0.5.0
File Size Uploaded
temporalis-0.5.0.tar.gz 54.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for temporalis 0.5.0
File Interpreter ABI Platform
temporalis-0.5.0-py3-none-any.whl Python 3 none any Details

Total release size: 100.1 kB

Release files / temporalis-0.5.0.tar.gz

Download URL temporalis-0.5.0.tar.gz
Size 54.9 kB
Tags Source
SHA-256 checksum
How to use checksums
8c736b96eb46e7bcae3ef0d6e985feb97ea480f53eabe65c417e5aee626f7638
BLAKE2b-256 checksum
How to use checksums
421fa2d5e1ac16098c3a404ad0199caa2833fdb31b0f31ad1cf99774d18a9c6d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.12

Release files / temporalis-0.5.0-py3-none-any.whl

Download URL temporalis-0.5.0-py3-none-any.whl
Size 45.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
3a9c649fb8a38635c5cabc7ce466a9aa1c6f2d5fe503ec2faeff5a2eff53692b
BLAKE2b-256 checksum
How to use checksums
0e3df86c56ae7038e07ff843e9080d3f5e6a4565c6d4ef91f15354c6b86eeee5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.12

Release history Release notifications | RSS feed

This release

0.5.0 This release

2 release files

0.1

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page