diff --git a/wetterdienst/core/timeseries/request.py b/wetterdienst/core/timeseries/request.py index abe0031e2..2c367bf8f 100644 --- a/wetterdienst/core/timeseries/request.py +++ b/wetterdienst/core/timeseries/request.py @@ -17,7 +17,6 @@ from polars.exceptions import NoDataError from rapidfuzz import fuzz, process -from build.lib.wetterdienst.metadata.metadata_model import DatasetModel from wetterdienst.core.core import Core from wetterdienst.core.timeseries.result import ( InterpolatedValuesResult, @@ -32,6 +31,7 @@ ) from wetterdienst.metadata.columns import Columns from wetterdienst.metadata.metadata_model import ( + DatasetModel, MetadataModel, ParameterModel, parse_parameter, diff --git a/wetterdienst/metadata/metadata_model.py b/wetterdienst/metadata/metadata_model.py index b2690e1ae..53087707a 100644 --- a/wetterdienst/metadata/metadata_model.py +++ b/wetterdienst/metadata/metadata_model.py @@ -59,7 +59,7 @@ def __getattr__(self, item): raise AttributeError(item) def __iter__(self) -> Iterator[ParameterModel]: - return iter(self.parameters) + return iter(parameter for parameter in self.parameters if not parameter.name.startswith("quality")) class ResolutionModel(BaseModel): @@ -145,11 +145,10 @@ class ParameterTemplate: @classmethod def parse(cls, value: str | Iterable[str] | DatasetModel | ParameterModel) -> ParameterTemplate: - print(type(value)) if isinstance(value, DatasetModel): return ParameterTemplate(value.resolution.name, value.name) if isinstance(value, ParameterModel): - return ParameterTemplate(value.dataset.resolution.value.value, value.dataset.name, value.name) + return ParameterTemplate(value.dataset.resolution.name, value.dataset.name, value.name) resolution = None dataset = None parameter = None @@ -171,12 +170,11 @@ def parse_parameter(parameter: _PARAMETER_TYPE, metadata: MetadataModel) -> list """Method to parse parameters, either from string or tuple or MetadataModel or sequence of those.""" parameters_found = [] for parameter in to_list(parameter): - print(parameter) parameter_template = ParameterTemplate.parse(parameter) try: parameters_found.extend(metadata.search_parameter(parameter_template)) except KeyError: - log.info(f"{parameter_template} not found in metadata") + log.info(f"{parameter_template} not found in {metadata.__class__}") unique_resolutions = set(parameter.dataset.resolution.value.value for parameter in parameters_found) # TODO: for now we only support one resolution if not len(unique_resolutions) == 1: diff --git a/wetterdienst/ui/streamlit/explorer/app.py b/wetterdienst/ui/streamlit/explorer/app.py index e4ddc8c91..8adaa688a 100644 --- a/wetterdienst/ui/streamlit/explorer/app.py +++ b/wetterdienst/ui/streamlit/explorer/app.py @@ -3,6 +3,7 @@ from __future__ import annotations import os +from typing import TYPE_CHECKING import duckdb import plotly.express as px @@ -11,10 +12,9 @@ from wetterdienst import Resolution, Settings, Wetterdienst, __version__ from wetterdienst.api import RequestRegistry -from wetterdienst.metadata.period import PeriodType -from wetterdienst.metadata.resolution import ResolutionType -from wetterdienst.provider.dwd.dmo import DwdDmoRequest -from wetterdienst.provider.dwd.mosmix import DwdMosmixRequest + +if TYPE_CHECKING: + from wetterdienst.metadata.metadata_model import MetadataModel # this env is set manually on streamlit.com LIVE = os.getenv("LIVE", "false").lower() == "true" @@ -36,16 +36,26 @@ """.strip() +@st.cache_resource +def get_api(provider: str, network: str): + return Wetterdienst(provider, network) + + +@st.cache_resource +def get_metadata(api: Wetterdienst): + return api.metadata + + def get_stations(provider: str, network: str, request_kwargs: dict): request_kwargs = request_kwargs.copy() request_kwargs["settings"] = Settings(**request_kwargs["settings"]) - return Wetterdienst(provider, network)(**request_kwargs).all() + return get_api(provider, network)(**request_kwargs).all() def get_station(provider: str, network: str, request_kwargs: dict, station_id: str): request_kwargs = request_kwargs.copy() request_kwargs["settings"] = Settings(**request_kwargs["settings"]) - return Wetterdienst(provider, network)(**request_kwargs).filter_by_station_id(station_id) + return get_api(provider, network)(**request_kwargs).filter_by_station_id(station_id) def get_values(provider: str, network: str, request_kwargs: dict, station_id: str): @@ -140,46 +150,45 @@ def create_plotly_fig( index=network_options.index("OBSERVATION") if "OBSERVATION" in network_options else 0, ) -api = Wetterdienst(provider, network) -resolution_options = [resolution.name for resolution in api.metadata] -resolution = st.selectbox( +api = get_api(provider, network) +metadata: MetadataModel = api.metadata + +resolution_options = [resolution.name for resolution in metadata] +resolution_choice = st.selectbox( "Select resolution", options=resolution_options, index=resolution_options.index("daily") if "daily" in resolution_options else 0, disabled=len(resolution_options) == 1, ) +resolution = metadata[resolution_choice] + # for hosted app, we disallow higher resolutions as the machine might not be able to handle it if LIVE: - if resolution in SUBDAILY_AT_MOST: + if resolution.value in SUBDAILY_AT_MOST: st.warning("Higher resolutions are disabled for hosted app. Choose at least daily resolution.") st.stop() -dataset_options = [dataset for dataset in api.metadata[resolution]] -dataset = st.selectbox( +dataset_options = [dataset.name for dataset in resolution] +dataset_choice = st.selectbox( "Select dataset", options=dataset_options, index=dataset_options.index("climate_summary") if "climate_summary" in dataset_options else 0, disabled=len(dataset_options) == 1, - format_func=lambda x: x.name, ) +dataset = resolution[dataset_choice] + +parameter_options = [parameter.name for parameter in dataset] +parameter_options = [dataset_choice] + parameter_options +parameter_choice = st.selectbox("Select parameter", options=parameter_options, index=0) -parameter_options = [parameter for parameter in api.metadata[resolution][dataset.name]] -parameter_options = [dataset] + parameter_options -parameter = st.selectbox("Select parameter", options=parameter_options, index=0, format_func=lambda x: x.name) +parameter = dataset if parameter_choice == dataset_choice else dataset[parameter_choice] -period_options = dataset.periods -# period = st.multiselect( -# "Select period", options=period_options, default=period_options, disabled=len(period_options) == 1, -# format_func=lambda x: x.value, -# ) # TODO: replace this with a general request kwargs resolver request_kwargs = { "parameter": parameter, "settings": settings, } -# if len(period) > 1: -# request_kwargs["period"] = period df_stations = get_stations(provider, network, request_kwargs).df if df_stations.is_empty(): diff --git a/wetterdienst/util/python.py b/wetterdienst/util/python.py index e980a5011..060474a9f 100644 --- a/wetterdienst/util/python.py +++ b/wetterdienst/util/python.py @@ -1,5 +1,7 @@ import collections.abc as collections_abc +from pydantic import BaseModel + string_types = (str,) binary_types = (bytes,) @@ -28,7 +30,11 @@ def to_list(x, default=None): """ if x is None: return default - if not isinstance(x, collections_abc.Iterable) or isinstance(x, string_types + binary_types): + if ( + not isinstance(x, collections_abc.Iterable) + or isinstance(x, string_types + binary_types) + or isinstance(x, BaseModel) + ): return [x] elif isinstance(x, list): return x