Layers (weather)
Weather data and grid image generation.
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() -> None
Close 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 |
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
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 |
required |
**options
|
|
{}
|
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 |
None
|
weather
|
WeatherDocument
|
A document from |
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 |
WeatherServiceError
|
For an |
WeatherModelInputsError
|
For |
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, |
required |
analysis_type
|
str
|
Registry analysis type used to pick the colours. Omit it to colour
the grid with the default |
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; |
DEFAULT_MAX_LONG_AXIS_PX
|
renderer
|
Any
|
Removed. Passing it raises |
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 ( |
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:<hex>".
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. |
required |
time_period
|
TimePeriod
|
The analysis window. |
required |
subtype
|
str
|
The analysis subtype, for analyses that have several. |
None
|
solar_model
|
str
|
|
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 ( |
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 |
Raises:
| Type | Description |
|---|---|
EpwParseError
|
For every file that is refused: no |