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

Python
logger: Logger = logger

Logger used for fetch, retry and debug messages.

base_url instance-attribute

Python
base_url: str = base_url

The service base URL passed at construction (unused by this client).

close

Python
close() -> None

Close the static reader's session.

get_weather_file_from_location

Python
get_weather_file_from_location(
*, lat: Latitude, lon: Longitude, radius: Optional[int] = None
)

Return the nearest public weather stations, nearest first.

Parameters:

NameTypeDescriptionDefault
latLatitudeLatitude of the point, in degrees.required
lonLongitudeLongitude of the point, in degrees.required
radiusintSearch radius in kilometres. Default 100.None

Returns:

TypeDescription
list of dictUp to 10 catalog rows (station metadata), nearest first.

Raises:

TypeDescription
WeatherServiceErrorIf the catalog cannot be fetched or decoded.

get_weather_file_from_identifier

Python
get_weather_file_from_identifier(*, identifier: str)

Return one public weather station's data by uuid or fileName.

Parameters:

NameTypeDescriptionDefault
identifierstrThe station's uuid or fileName in the public catalog.required

Returns:

TypeDescription
dictThe station's data object.

Raises:

TypeDescription
WeatherServiceErrorIf 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

Python
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:

NameTypeDescriptionDefault
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
**optionsmax_bytes and max_rows: tighten the size and row bounds. See parse_epw.{}

Returns:

TypeDescription
WeatherDocumentThe validated weather document.

Raises:

TypeDescription
EpwParseErrorIf the file is unreadable or not a usable EPW file.

filter_weather_data

Python
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:

NameTypeDescriptionDefault
identifierstrA public catalog station, by uuid or fileName.None
weatherWeatherDocumentA document from parse_epw.None
time_periodTimePeriodThe window: a date span with a daily hour range.required

Returns:

TypeDescription
list of WeatherDataPointOne record per hour inside the window.

Raises:

TypeDescription
ValueErrorIf neither or both of identifier and weather are given.
WeatherServiceErrorFor an identifier: if it is not in the public catalog, or the catalog or station cannot be fetched or decoded.
WeatherModelInputsErrorFor weather: if the document cannot be filtered to the window.

gen_grid_image

Python
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:

NameTypeDescriptionDefault
gridsequence of sequenceRows of cells: numbers, None (no data), or wind-comfort class labels ("A".."E", "S", "S15", "S20").required
analysis_typestrRegistry analysis type used to pick the colours. Omit it to colour the grid with the default magma_r ramp.None
criteriastrCriteria key for an analysis type with several variants.None
subtypestrSubtype key for an analysis type with several subtypes.None
max_long_axis_pxintCap 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
rendererAnyRemoved. Passing it raises TypeError.REMOVED

Returns:

TypeDescription
bytesThe PNG file contents.

Raises:

TypeDescription
WeatherServiceErrorIf 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:

NameTypeDescription
documentdictThe parsed file as plain data (schema, location, period, time, fields, values, missing and identity), so it round-trips through json.
source_pathstr or NoneWhere 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

Python
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:

TypeDescription
EpwParseErrorIf the document is too malformed to have an identity.

location property

Python
location: Mapping[str, Any]

The EPW LOCATION header, as the document records it.

period property

Python
period: Mapping[str, Any]

Row count, records per hour, leap-year and full-year verdicts.

rows property

Python
rows: int

Data rows in the file, before any window is applied.

to_dict

Python
to_dict() -> Dict[str, Any]

Return the document itself, as plain data.

Serialise it with json.dumps.

filter_hours

Python
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:

NameTypeDescriptionDefault
time_periodTimePeriodThe analysis window.required

Returns:

TypeDescription
list of WeatherDataPointOne record per hour inside the window.

Raises:

TypeDescription
WeatherModelInputsErrorIf the file cannot be filtered to that window.

model_inputs

Python
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:

NameTypeDescriptionDefault
analysis_typestrThe analysis type, e.g. "thermal-comfort-index".required
time_periodTimePeriodThe analysis window.required
subtypestrThe analysis subtype, for analyses that have several.None
solar_modelstr"legacy-flat" or "irradiance"; only valid for analysis_type="energy-balance".None

Returns:

TypeDescription
dictThe weather arrays the model reads, keyed by snake_case field name.

Raises:

TypeDescription
WeatherModelInputsErrorIf 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

Python
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:

NameTypeDescriptionDefault
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_bytesintLower the built-in size bound (16 MiB). It may only be TIGHTENED; asking for a wider bound raises rather than being ignored.None
max_rowsintLower the built-in row bound (8784 rows). It may only be TIGHTENED; asking for a wider bound raises rather than being ignored.None

Returns:

TypeDescription
WeatherDocumentThe validated document, ready for from_weatherfile_payload.

Raises:

TypeDescription
EpwParseErrorFor 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.