WeatherServiceClient
Bases: ScrubbedSessionState
Client for weather data and grid-image generation.
static_base_url selects the public catalog host. api_key, base_url and gateway_base_url are accepted for construction compatibility with the other service clients and are unused: the catalog is public, and no credential ever goes to that host.
logger instance-attribute
logger: Logger = logger
Logger used for fetch, retry and debug messages.
base_url instance-attribute
base_url: str = base_url
The service base URL passed at construction (unused by this client).
close
close() -> NoneClose the static reader's session.
get_weather_file_from_location
get_weather_file_from_location(
*, lat: Latitude, lon: Longitude, radius: Optional[int] = None
)Return the nearest public weather stations, nearest first.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
lat | Latitude | Latitude of the point, in degrees. | required |
lon | Longitude | Longitude of the point, in degrees. | required |
radius | int | Search radius in kilometres. Default 100. | None |
Returns:
| Type | Description |
|---|---|
list of dict | Up to 10 catalog rows (station metadata), nearest first. |
Raises:
| Type | Description |
|---|---|
WeatherServiceError | If the catalog cannot be fetched or decoded. |
get_weather_file_from_identifier
get_weather_file_from_identifier(*, identifier: str)
Return one public weather station's data by uuid or fileName.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
identifier | str | The station's uuid or fileName in the public catalog. | required |
Returns:
| Type | Description |
|---|---|
dict | The station's data object. |
Raises:
| Type | Description |
|---|---|
WeatherServiceError | If the identifier is not in the public catalog, or the catalog or station cannot be fetched or decoded. Private and custom-EPW files are not in the catalog; use parse_epw for those. |
parse_epw
parse_epw(source, **options)
Read one local .epw file and validate it.
The bring-your-own weather entry point, and the only one for a file that is not in the public catalog. Nothing is uploaded, nothing is registered and no request leaves this process. Pass the returned WeatherDocument straight to from_weatherfile_payload and keep it for the retry, because its identity is what proves a resume uses the same weather.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source | (str, bytes, bytearray or PathLike) | A path to the .epw file, or the file's text (a str with a line end, or bytes). | required |
**options | max_bytes and max_rows: tighten the size and row bounds. See parse_epw. | {} |
Returns:
| Type | Description |
|---|---|
WeatherDocument | The validated weather document. |
Raises:
| Type | Description |
|---|---|
EpwParseError | If the file is unreadable or not a usable EPW file. |
filter_weather_data
filter_weather_data( *, identifier: Optional[str] = None, weather: Any = None, time_period: TimePeriod, )
Return weather filtered to time_period, one record per hour.
Give EITHER identifier (a public catalog station, by uuid or fileName) OR weather (a WeatherDocument from parse_epw). The BYO document is accepted everywhere a station id is, runs entirely on your machine and makes no request at all; the window means the same thing for both.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
identifier | str | A public catalog station, by uuid or fileName. | None |
weather | WeatherDocument | A document from parse_epw. | None |
time_period | TimePeriod | The window: a date span with a daily hour range. | required |
Returns:
| Type | Description |
|---|---|
list of WeatherDataPoint | One record per hour inside the window. |
Raises:
| Type | Description |
|---|---|
ValueError | If neither or both of identifier and weather are given. |
WeatherServiceError | For an identifier: if it is not in the public catalog, or the catalog or station cannot be fetched or decoded. |
WeatherModelInputsError | For weather: if the document cannot be filtered to the window. |
gen_grid_image
gen_grid_image( *, grid: Sequence[Sequence[Any]], analysis_type: Optional[str] = None, criteria: Optional[str] = None, subtype: Optional[str] = None, max_long_axis_px: Optional[int] = DEFAULT_MAX_LONG_AXIS_PX, renderer: Any = REMOVED, )
Render a result grid to a PNG and return the raw PNG bytes.
The grid is coloured with the public colour registry (registry.infrared.city; no API key, cached per process) for the analysis type you name. The image is 1:1, one pixel per grid cell, up to a 960 px long axis. A failure raises WeatherServiceError; you never get a fallback-coloured image when the registry colours cannot be loaded.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
grid | sequence of sequence | Rows of cells: numbers, None (no data), or wind-comfort class labels ("A".."E", "S", "S15", "S20"). | required |
analysis_type | str | Registry analysis type used to pick the colours. Omit it to colour the grid with the default magma_r ramp. | None |
criteria | str | Criteria key for an analysis type with several variants. | None |
subtype | str | Subtype key for an analysis type with several subtypes. | None |
max_long_axis_px | int | Cap on the long axis of the image, in pixels. Default 960. A larger grid is sampled nearest-neighbour on the VALUES, so it keeps its aspect ratio and its no-data cells; None or 0 renders every cell. Read the image size and the scale factor with infrared_sdk.layers.image_local.grid_image_size. | DEFAULT_MAX_LONG_AXIS_PX |
renderer | Any | Removed. Passing it raises TypeError. | REMOVED |
Returns:
| Type | Description |
|---|---|
bytes | The PNG file contents. |
Raises:
| Type | Description |
|---|---|
WeatherServiceError | If the grid is malformed, the colour registry cannot be loaded, or rendering fails. |
EpwParseError
Bases: ValueError
An EPW file that was refused, with the reason.
A ValueError subclass, so a caller that already catches ValueError around parse_epw keeps working. The named type is what lets a caller separate a bad FILE from a bad request.
WeatherDocument
One validated EPW file.
Hold it, pass it to a payload builder, and keep it for the retry: its identity is what proves a resumed run uses the same weather as the run it resumes.
Warnings
The identity is computed on every read, never cached. The document is a plain dict you can reach and change, and if you edit it after submitting, the retry is refused rather than served a stale digest that says the weather is unchanged. Computing it hashes the weather columns; it does not re-parse the file.
Attributes:
| Name | Type | Description |
|---|---|---|
document | dict | The parsed file as plain data (schema, location, period, time, fields, values, missing and identity), so it round-trips through json. |
source_path | str or None | Where the bytes came from, used in messages. It is never hashed: two copies of one file under two names are the same weather. |
identity property
identity: str
The versioned weather identity, "sha256:.
It covers the validated values, their order, the location, the calendar columns and the hour basis, and never the file name, a station id or the raw text, so two differently formatted files with the same readings share one identity.
Raises:
| Type | Description |
|---|---|
EpwParseError | If the document is too malformed to have an identity. |
location property
location: Mapping[str, Any]
The EPW LOCATION header, as the document records it.
period property
period: Mapping[str, Any]
Row count, records per hour, leap-year and full-year verdicts.
rows property
rows: int
Data rows in the file, before any window is applied.
to_dict
to_dict() -> Dict[str, Any]
Return the document itself, as plain data.
Serialise it with json.dumps.
filter_hours
filter_hours(time_period: TimePeriod) -> List[WeatherDataPoint]
Return the file's hours inside time_period, one record per hour.
The same shape WeatherServiceClient.filter_weather_data returns for a public station, from a local file and with no network call. The window is a date span with a daily hour range, exactly the hours the model counts. A window that crosses the year end (for example 1 December to 28 February) keeps its hours in calendar order of the year: January, February, then December.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
time_period | TimePeriod | The analysis window. | required |
Returns:
| Type | Description |
|---|---|
list of WeatherDataPoint | One record per hour inside the window. |
Raises:
| Type | Description |
|---|---|
WeatherModelInputsError | If the file cannot be filtered to that window. |
model_inputs
model_inputs( *, analysis_type: str, time_period: TimePeriod, subtype: Optional[str] = None, solar_model: Optional[str] = None, ) -> Dict[str, Any]
Return the snake_case weather arrays one model reads, for one window.
The window is applied first, then the required fields are checked on the FILTERED rows, then the period rule, so a gap outside the window is harmless, a gap inside it raises, and a model that needs a full year raises on a shorter one.
solar_model belongs to analysis_type="energy-balance", the one analysis that reads it; on any other analysis it raises, because nothing would read it there. solar_model="irradiance" selects the interior-irradiance input set and its full-year rule; omitted, or "legacy-flat", selects the two climate arrays that model reads.
To RUN energy-balance with a file, use from_weather, which calls this method with the full-year window and the request's own solar_model.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
analysis_type | str | The analysis type, e.g. "thermal-comfort-index". | required |
time_period | TimePeriod | The analysis window. | required |
subtype | str | The analysis subtype, for analyses that have several. | None |
solar_model | str | "legacy-flat" or "irradiance"; only valid for analysis_type="energy-balance". | None |
Returns:
| Type | Description |
|---|---|
dict | The weather arrays the model reads, keyed by snake_case field name. |
Raises:
| Type | Description |
|---|---|
WeatherModelInputsError | If the document cannot supply what the model needs for this window. |
WeatherModelInputsError
Bases: ValueError
The document cannot supply what the requested model needs.
Raised for a gap in a required column inside the selected window, for a window shorter than a full year where the model needs one, and for an analysis that has no weather input set. Always raised before submission.
parse_epw
parse_epw( source: Union[str, bytes, bytearray, PathLike], *, max_bytes: Optional[int] = None, max_rows: Optional[int] = None, ) -> WeatherDocument
Read and validate one .epw file, and return its document.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source | (str, bytes, bytearray or PathLike) | A path (str without a line end, or Path), or the file's text (str with a line end, or bytes). | required |
max_bytes | int | Lower the built-in size bound (16 MiB). It may only be TIGHTENED; asking for a wider bound raises rather than being ignored. | None |
max_rows | int | Lower the built-in row bound (8784 rows). It may only be TIGHTENED; asking for a wider bound raises rather than being ignored. | None |
Returns:
| Type | Description |
|---|---|
WeatherDocument | The validated document, ready for from_weatherfile_payload. |
Raises:
| Type | Description |
|---|---|
EpwParseError | For every file that is refused: no LOCATION header, a location number out of range, sub-hourly data, a row shorter than 22 columns, an hour outside 1-24, a calendar cell that is not a number, or a file over the size or row bound. The message names the row or the field. |