From 56c8be85df56649d9c898aad1ceda48f4aa414f1 Mon Sep 17 00:00:00 2001 From: Sylvain Brunato Date: Mon, 19 Feb 2024 14:12:19 +0100 Subject: [PATCH] fix: add defaults to cds queryables --- docs/notebooks/api_user_guide/4_search.ipynb | 96 ++++++++++++-------- eodag/plugins/apis/base.py | 22 ++++- eodag/plugins/apis/cds.py | 20 ++-- eodag/plugins/search/base.py | 21 ++++- tests/units/test_apis_plugins.py | 4 +- tests/units/test_http_server.py | 2 +- 6 files changed, 109 insertions(+), 56 deletions(-) diff --git a/docs/notebooks/api_user_guide/4_search.ipynb b/docs/notebooks/api_user_guide/4_search.ipynb index e2b9f7ae26..d10e178286 100644 --- a/docs/notebooks/api_user_guide/4_search.ipynb +++ b/docs/notebooks/api_user_guide/4_search.ipynb @@ -26,15 +26,15 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2024-02-08 10:34:01,758 eodag.config [INFO ] Loading user configuration from: /home/user/.config/eodag/eodag.yml\n", - "2024-02-08 10:34:01,984 eodag.core [INFO ] Locations configuration loaded from /home/user/.config/eodag/locations.yml\n" + "2024-02-19 12:00:29,455 eodag.config [INFO ] Loading user configuration from: /home/sylvain/.config/eodag/eodag.yml\n", + "2024-02-19 12:00:29,545 eodag.core [INFO ] Locations configuration loaded from /home/sylvain/.config/eodag/locations.yml\n" ] } ], @@ -2513,7 +2513,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 2, "metadata": {}, "outputs": [ { @@ -2526,7 +2526,7 @@ " 'geom': typing.Annotated[typing.Optional[str], FieldInfo(annotation=NoneType, required=False, alias='geometry', alias_priority=2)]}" ] }, - "execution_count": 3, + "execution_count": 2, "metadata": {}, "output_type": "execute_result" } @@ -2544,24 +2544,26 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "{'end': typing.Annotated[typing.Optional[str], FieldInfo(annotation=NoneType, required=False, alias='completionTimeFromAscendingNode', alias_priority=2)],\n", - " 'sky_type': typing.Annotated[typing.Literal['clear', 'observed_cloud'], FieldInfo(annotation=NoneType, required=False, default='clear')],\n", - " 'format': typing.Annotated[typing.Literal['csv', 'netcdf'], FieldInfo(annotation=NoneType, required=False, default='csv')],\n", - " 'time_reference': typing.Annotated[typing.Literal['true_solar_time', 'universal_time'], FieldInfo(annotation=NoneType, required=False, default='true_solar_time')],\n", + "{'sky_type': typing.Annotated[typing.Literal['clear', 'observed_cloud'], FieldInfo(annotation=NoneType, required=False, default='clear')],\n", " 'time_step': typing.Annotated[typing.Literal['15minute', '1day', '1hour', '1minute', '1month'], FieldInfo(annotation=NoneType, required=False, default='1minute')],\n", - " 'productType': typing.Annotated[str, FieldInfo(annotation=NoneType, required=True)],\n", + " 'time_reference': typing.Annotated[typing.Literal['true_solar_time', 'universal_time'], FieldInfo(annotation=NoneType, required=False, default='true_solar_time')],\n", + " 'location': typing.Annotated[dict, FieldInfo(annotation=NoneType, required=False, default={'latitude': 0, 'longitude': 0})],\n", + " 'altitude': typing.Annotated[int, FieldInfo(annotation=NoneType, required=False, default=-999)],\n", + " 'format': typing.Annotated[typing.Literal['csv', 'netcdf'], FieldInfo(annotation=NoneType, required=False, default='csv')],\n", + " 'end': typing.Annotated[typing.Optional[str], FieldInfo(annotation=NoneType, required=False, alias='completionTimeFromAscendingNode', alias_priority=2)],\n", " 'geom': typing.Annotated[typing.Optional[str], FieldInfo(annotation=NoneType, required=False, alias='geometry', alias_priority=2)],\n", + " 'productType': typing.Annotated[str, FieldInfo(annotation=NoneType, required=False, default='CAMS_SOLAR_RADIATION')],\n", " 'id': typing.Annotated[typing.Optional[str], FieldInfo(annotation=NoneType, required=False)],\n", " 'start': typing.Annotated[typing.Optional[str], FieldInfo(annotation=NoneType, required=False, alias='startTimeFromAscendingNode', alias_priority=2)]}" ] }, - "execution_count": 4, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" } @@ -2579,14 +2581,14 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2024-02-08 10:43:38,885 eodag.search.qssearch [INFO ] Fetching queryables: https://planetarycomputer.microsoft.com/api/stac/v1/search/../collections/sentinel-1-grd/queryables\n" + "2024-02-19 12:01:07,071 eodag.search.qssearch [INFO ] Fetching queryables: https://planetarycomputer.microsoft.com/api/stac/v1/search/../collections/sentinel-1-grd/queryables\n" ] }, { @@ -2597,10 +2599,10 @@ " 'geom': typing.Annotated[typing.Optional[str], FieldInfo(annotation=NoneType, required=False, alias='geometry', alias_priority=2)],\n", " 'platform': typing.Annotated[typing.Optional[str], FieldInfo(annotation=NoneType, required=False)],\n", " 's1:shape': typing.Annotated[list, FieldInfo(annotation=NoneType, required=False)],\n", - " 'end_datetime': typing.Annotated[str, FieldInfo(annotation=NoneType, required=False, title='End datetime', description='End datetime', metadata=[_PydanticGeneralMetadata(pattern='(\\\\+00:00|Z)$')])],\n", + " 'end_datetime': typing.Annotated[str, FieldInfo(annotation=NoneType, required=False, title='End datetime', description='End datetime', metadata=[PydanticGeneralMetadata(pattern='(\\\\+00:00|Z)$')])],\n", " 's1:resolution': typing.Annotated[typing.Literal['full', 'high', 'medium'], FieldInfo(annotation=NoneType, required=False, title='Resolution')],\n", " 's1:datatake_id': typing.Annotated[str, FieldInfo(annotation=NoneType, required=False, title='Datatake ID')],\n", - " 'start_datetime': typing.Annotated[str, FieldInfo(annotation=NoneType, required=False, title='Start datetime', description='Start datetime', metadata=[_PydanticGeneralMetadata(pattern='(\\\\+00:00|Z)$')])],\n", + " 'start_datetime': typing.Annotated[str, FieldInfo(annotation=NoneType, required=False, title='Start datetime', description='Start datetime', metadata=[PydanticGeneralMetadata(pattern='(\\\\+00:00|Z)$')])],\n", " 's1:orbit_source': typing.Annotated[typing.Literal['DOWNLINK', 'POEORB', 'PREORB', 'RESORB'], FieldInfo(annotation=NoneType, required=False, title='Orbit Source')],\n", " 's1:slice_number': typing.Annotated[str, FieldInfo(annotation=NoneType, required=False, title='Slice Number')],\n", " 's1:total_slices': typing.Annotated[str, FieldInfo(annotation=NoneType, required=False, title='Total Slices')],\n", @@ -2624,7 +2626,7 @@ " 'sar:looks_equivalent_number': typing.Annotated[float, FieldInfo(annotation=NoneType, required=False, title='Equivalent number of looks (ENL)')],\n", " 's1:instrument_configuration_ID': typing.Annotated[str, FieldInfo(annotation=NoneType, required=False)],\n", " 'sat:platform_international_designator': typing.Annotated[typing.Literal['0000-000A', '2014-016A', '2016-025A'], FieldInfo(annotation=NoneType, required=False, title='Platform Designation')],\n", - " 'productType': typing.Annotated[str, FieldInfo(annotation=NoneType, required=True)],\n", + " 'productType': typing.Annotated[str, FieldInfo(annotation=NoneType, required=False, default='S1_SAR_GRD')],\n", " 'doi': typing.Annotated[typing.Optional[str], FieldInfo(annotation=NoneType, required=False)],\n", " 'platformSerialIdentifier': typing.Annotated[typing.Optional[str], FieldInfo(annotation=NoneType, required=False)],\n", " 'instrument': typing.Annotated[typing.Optional[str], FieldInfo(annotation=NoneType, required=False)],\n", @@ -2643,7 +2645,7 @@ " 'start': typing.Annotated[typing.Optional[str], FieldInfo(annotation=NoneType, required=False, alias='startTimeFromAscendingNode', alias_priority=2)]}" ] }, - "execution_count": 5, + "execution_count": 4, "metadata": {}, "output_type": "execute_result" } @@ -2661,32 +2663,37 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "{'day': typing.Annotated[typing.Literal['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29'], FieldInfo(annotation=NoneType, required=False)],\n", - " 'month': typing.Annotated[typing.Literal['02'], FieldInfo(annotation=NoneType, required=False, default='02')],\n", - " 'api_product_type': typing.Annotated[typing.Literal['ensemble_mean', 'ensemble_members', 'ensemble_spread', 'reanalysis'], FieldInfo(annotation=NoneType, required=False, default='reanalysis')],\n", + "{'api_product_type': typing.Annotated[typing.Literal['reanalysis'], FieldInfo(annotation=NoneType, required=False, default='reanalysis')],\n", " 'time': typing.Annotated[typing.Literal['00:00', '01:00', '02:00', '03:00', '04:00', '05:00', '06:00', '07:00', '08:00', '09:00', '10:00', '11:00', '12:00', '13:00', '14:00', '15:00', '16:00', '17:00', '18:00', '19:00', '20:00', '21:00', '22:00', '23:00'], FieldInfo(annotation=NoneType, required=False, default='00:00')],\n", - " 'variable': typing.Annotated[typing.Literal['100m_u_component_of_wind', '100m_v_component_of_wind', '10m_u_component_of_neutral_wind', '10m_u_component_of_wind', '10m_v_component_of_neutral_wind', '10m_v_component_of_wind', '10m_wind_gust_since_previous_post_processing', '2m_dewpoint_temperature', '2m_temperature', 'air_density_over_the_oceans', 'angle_of_sub_gridscale_orography', 'anisotropy_of_sub_gridscale_orography', 'benjamin_feir_index', 'boundary_layer_dissipation', 'boundary_layer_height', 'charnock', 'clear_sky_direct_solar_radiation_at_surface', 'cloud_base_height', 'coefficient_of_drag_with_waves', 'convective_available_potential_energy', 'convective_inhibition', 'convective_precipitation', 'convective_rain_rate', 'convective_snowfall', 'convective_snowfall_rate_water_equivalent', 'downward_uv_radiation_at_the_surface', 'duct_base_height', 'eastward_gravity_wave_surface_stress', 'eastward_turbulent_surface_stress', 'evaporation', 'forecast_albedo', 'forecast_logarithm_of_surface_roughness_for_heat', 'forecast_surface_roughness', 'free_convective_velocity_over_the_oceans', 'friction_velocity', 'geopotential', 'gravity_wave_dissipation', 'high_cloud_cover', 'high_vegetation_cover', 'ice_temperature_layer_1', 'ice_temperature_layer_2', 'ice_temperature_layer_3', 'ice_temperature_layer_4', 'instantaneous_10m_wind_gust', 'instantaneous_eastward_turbulent_surface_stress', 'instantaneous_large_scale_surface_precipitation_fraction', 'instantaneous_moisture_flux', 'instantaneous_northward_turbulent_surface_stress', 'instantaneous_surface_sensible_heat_flux', 'k_index', 'lake_bottom_temperature', 'lake_cover', 'lake_depth', 'lake_ice_depth', 'lake_ice_temperature', 'lake_mix_layer_depth', 'lake_mix_layer_temperature', 'lake_shape_factor', 'lake_total_layer_temperature', 'land_sea_mask', 'large_scale_precipitation', 'large_scale_precipitation_fraction', 'large_scale_rain_rate', 'large_scale_snowfall', 'large_scale_snowfall_rate_water_equivalent', 'leaf_area_index_high_vegetation', 'leaf_area_index_low_vegetation', 'low_cloud_cover', 'low_vegetation_cover', 'maximum_2m_temperature_since_previous_post_processing', 'maximum_individual_wave_height', 'maximum_total_precipitation_rate_since_previous_post_processing', 'mean_boundary_layer_dissipation', 'mean_convective_precipitation_rate', 'mean_convective_snowfall_rate', 'mean_direction_of_total_swell', 'mean_direction_of_wind_waves', 'mean_eastward_gravity_wave_surface_stress', 'mean_eastward_turbulent_surface_stress', 'mean_evaporation_rate', 'mean_gravity_wave_dissipation', 'mean_large_scale_precipitation_fraction', 'mean_large_scale_precipitation_rate', 'mean_large_scale_snowfall_rate', 'mean_northward_gravity_wave_surface_stress', 'mean_northward_turbulent_surface_stress', 'mean_period_of_total_swell', 'mean_period_of_wind_waves', 'mean_potential_evaporation_rate', 'mean_runoff_rate', 'mean_sea_level_pressure', 'mean_snow_evaporation_rate', 'mean_snowfall_rate', 'mean_snowmelt_rate', 'mean_square_slope_of_waves', 'mean_sub_surface_runoff_rate', 'mean_surface_direct_short_wave_radiation_flux', 'mean_surface_direct_short_wave_radiation_flux_clear_sky', 'mean_surface_downward_long_wave_radiation_flux', 'mean_surface_downward_long_wave_radiation_flux_clear_sky', 'mean_surface_downward_short_wave_radiation_flux', 'mean_surface_downward_short_wave_radiation_flux_clear_sky', 'mean_surface_downward_uv_radiation_flux', 'mean_surface_latent_heat_flux', 'mean_surface_net_long_wave_radiation_flux', 'mean_surface_net_long_wave_radiation_flux_clear_sky', 'mean_surface_net_short_wave_radiation_flux', 'mean_surface_net_short_wave_radiation_flux_clear_sky', 'mean_surface_runoff_rate', 'mean_surface_sensible_heat_flux', 'mean_top_downward_short_wave_radiation_flux', 'mean_top_net_long_wave_radiation_flux', 'mean_top_net_long_wave_radiation_flux_clear_sky', 'mean_top_net_short_wave_radiation_flux', 'mean_top_net_short_wave_radiation_flux_clear_sky', 'mean_total_precipitation_rate', 'mean_vertical_gradient_of_refractivity_inside_trapping_layer', 'mean_vertically_integrated_moisture_divergence', 'mean_wave_direction', 'mean_wave_direction_of_first_swell_partition', 'mean_wave_direction_of_second_swell_partition', 'mean_wave_direction_of_third_swell_partition', 'mean_wave_period', 'mean_wave_period_based_on_first_moment', 'mean_wave_period_based_on_first_moment_for_swell', 'mean_wave_period_based_on_first_moment_for_wind_waves', 'mean_wave_period_based_on_second_moment_for_swell', 'mean_wave_period_based_on_second_moment_for_wind_waves', 'mean_wave_period_of_first_swell_partition', 'mean_wave_period_of_second_swell_partition', 'mean_wave_period_of_third_swell_partition', 'mean_zero_crossing_wave_period', 'medium_cloud_cover', 'minimum_2m_temperature_since_previous_post_processing', 'minimum_total_precipitation_rate_since_previous_post_processing', 'minimum_vertical_gradient_of_refractivity_inside_trapping_layer', 'model_bathymetry', 'near_ir_albedo_for_diffuse_radiation', 'near_ir_albedo_for_direct_radiation', 'normalized_energy_flux_into_ocean', 'normalized_energy_flux_into_waves', 'normalized_stress_into_ocean', 'northward_gravity_wave_surface_stress', 'northward_turbulent_surface_stress', 'ocean_surface_stress_equivalent_10m_neutral_wind_direction', 'ocean_surface_stress_equivalent_10m_neutral_wind_speed', 'peak_wave_period', 'period_corresponding_to_maximum_individual_wave_height', 'potential_evaporation', 'precipitation_type', 'runoff', 'sea_ice_cover', 'sea_surface_temperature', 'significant_height_of_combined_wind_waves_and_swell', 'significant_height_of_total_swell', 'significant_height_of_wind_waves', 'significant_wave_height_of_first_swell_partition', 'significant_wave_height_of_second_swell_partition', 'significant_wave_height_of_third_swell_partition', 'skin_reservoir_content', 'skin_temperature', 'slope_of_sub_gridscale_orography', 'snow_albedo', 'snow_density', 'snow_depth', 'snow_evaporation', 'snowfall', 'snowmelt', 'soil_temperature_level_1', 'soil_temperature_level_2', 'soil_temperature_level_3', 'soil_temperature_level_4', 'soil_type', 'standard_deviation_of_filtered_subgrid_orography', 'standard_deviation_of_orography', 'sub_surface_runoff', 'surface_latent_heat_flux', 'surface_net_solar_radiation', 'surface_net_solar_radiation_clear_sky', 'surface_net_thermal_radiation', 'surface_net_thermal_radiation_clear_sky', 'surface_pressure', 'surface_runoff', 'surface_sensible_heat_flux', 'surface_solar_radiation_downward_clear_sky', 'surface_solar_radiation_downwards', 'surface_thermal_radiation_downward_clear_sky', 'surface_thermal_radiation_downwards', 'temperature_of_snow_layer', 'toa_incident_solar_radiation', 'top_net_solar_radiation', 'top_net_solar_radiation_clear_sky', 'top_net_thermal_radiation', 'top_net_thermal_radiation_clear_sky', 'total_cloud_cover', 'total_column_cloud_ice_water', 'total_column_cloud_liquid_water', 'total_column_ozone', 'total_column_rain_water', 'total_column_snow_water', 'total_column_supercooled_liquid_water', 'total_column_water', 'total_column_water_vapour', 'total_precipitation', 'total_sky_direct_solar_radiation_at_surface', 'total_totals_index', 'trapping_layer_base_height', 'trapping_layer_top_height', 'type_of_high_vegetation', 'type_of_low_vegetation', 'u_component_stokes_drift', 'uv_visible_albedo_for_diffuse_radiation', 'uv_visible_albedo_for_direct_radiation', 'v_component_stokes_drift', 'vertical_integral_of_divergence_of_cloud_frozen_water_flux', 'vertical_integral_of_divergence_of_cloud_liquid_water_flux', 'vertical_integral_of_divergence_of_geopotential_flux', 'vertical_integral_of_divergence_of_kinetic_energy_flux', 'vertical_integral_of_divergence_of_mass_flux', 'vertical_integral_of_divergence_of_moisture_flux', 'vertical_integral_of_divergence_of_ozone_flux', 'vertical_integral_of_divergence_of_thermal_energy_flux', 'vertical_integral_of_divergence_of_total_energy_flux', 'vertical_integral_of_eastward_cloud_frozen_water_flux', 'vertical_integral_of_eastward_cloud_liquid_water_flux', 'vertical_integral_of_eastward_geopotential_flux', 'vertical_integral_of_eastward_heat_flux', 'vertical_integral_of_eastward_kinetic_energy_flux', 'vertical_integral_of_eastward_mass_flux', 'vertical_integral_of_eastward_ozone_flux', 'vertical_integral_of_eastward_total_energy_flux', 'vertical_integral_of_eastward_water_vapour_flux', 'vertical_integral_of_energy_conversion', 'vertical_integral_of_kinetic_energy', 'vertical_integral_of_mass_of_atmosphere', 'vertical_integral_of_mass_tendency', 'vertical_integral_of_northward_cloud_frozen_water_flux', 'vertical_integral_of_northward_cloud_liquid_water_flux', 'vertical_integral_of_northward_geopotential_flux', 'vertical_integral_of_northward_heat_flux', 'vertical_integral_of_northward_kinetic_energy_flux', 'vertical_integral_of_northward_mass_flux', 'vertical_integral_of_northward_ozone_flux', 'vertical_integral_of_northward_total_energy_flux', 'vertical_integral_of_northward_water_vapour_flux', 'vertical_integral_of_potential_and_internal_energy', 'vertical_integral_of_potential_internal_and_latent_energy', 'vertical_integral_of_temperature', 'vertical_integral_of_thermal_energy', 'vertical_integral_of_total_energy', 'vertically_integrated_moisture_divergence', 'volumetric_soil_water_layer_1', 'volumetric_soil_water_layer_2', 'volumetric_soil_water_layer_3', 'volumetric_soil_water_layer_4', 'wave_spectral_directional_width', 'wave_spectral_directional_width_for_swell', 'wave_spectral_directional_width_for_wind_waves', 'wave_spectral_kurtosis', 'wave_spectral_peakedness', 'wave_spectral_skewness', 'zero_degree_level'], FieldInfo(annotation=NoneType, required=False)],\n", - " 'year': typing.Annotated[typing.Literal['1940', '1941', '1942', '1943', '1944', '1945', '1946', '1947', '1948', '1949', '1950', '1951', '1952', '1953', '1954', '1955', '1956', '1957', '1958', '1959', '1960', '1961', '1962', '1963', '1964', '1965', '1966', '1967', '1968', '1969', '1970', '1971', '1972', '1973', '1974', '1975', '1976', '1977', '1978', '1979', '1980', '1981', '1982', '1983', '1984', '1985', '1986', '1987', '1988', '1989', '1990', '1991', '1992', '1993', '1994', '1995', '1996', '1997', '1998', '1999', '2000', '2001', '2002', '2003', '2004', '2005', '2006', '2007', '2008', '2009', '2010', '2011', '2012', '2013', '2014', '2015', '2016', '2017', '2018', '2019', '2020', '2021', '2022', '2023', '2024'], FieldInfo(annotation=NoneType, required=False)],\n", - " 'productType': typing.Annotated[str, FieldInfo(annotation=NoneType, required=True)],\n", + " 'format': typing.Annotated[str, FieldInfo(annotation=NoneType, required=False, default='grib')],\n", + " 'month': typing.Annotated[typing.Literal['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'], FieldInfo(annotation=NoneType, required=False, default='02')],\n", + " 'day': typing.Annotated[typing.Literal['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29'], FieldInfo(annotation=NoneType, required=True)],\n", + " 'variable': typing.Annotated[typing.Literal['100m_u_component_of_wind', '100m_v_component_of_wind', '10m_u_component_of_neutral_wind', '10m_u_component_of_wind', '10m_v_component_of_neutral_wind', '10m_v_component_of_wind', '10m_wind_gust_since_previous_post_processing', '2m_dewpoint_temperature', '2m_temperature', 'air_density_over_the_oceans', 'angle_of_sub_gridscale_orography', 'anisotropy_of_sub_gridscale_orography', 'benjamin_feir_index', 'boundary_layer_dissipation', 'boundary_layer_height', 'charnock', 'clear_sky_direct_solar_radiation_at_surface', 'cloud_base_height', 'coefficient_of_drag_with_waves', 'convective_available_potential_energy', 'convective_inhibition', 'convective_precipitation', 'convective_rain_rate', 'convective_snowfall', 'convective_snowfall_rate_water_equivalent', 'downward_uv_radiation_at_the_surface', 'duct_base_height', 'eastward_gravity_wave_surface_stress', 'eastward_turbulent_surface_stress', 'evaporation', 'forecast_albedo', 'forecast_logarithm_of_surface_roughness_for_heat', 'forecast_surface_roughness', 'free_convective_velocity_over_the_oceans', 'friction_velocity', 'geopotential', 'gravity_wave_dissipation', 'high_cloud_cover', 'high_vegetation_cover', 'ice_temperature_layer_1', 'ice_temperature_layer_2', 'ice_temperature_layer_3', 'ice_temperature_layer_4', 'instantaneous_10m_wind_gust', 'instantaneous_eastward_turbulent_surface_stress', 'instantaneous_large_scale_surface_precipitation_fraction', 'instantaneous_moisture_flux', 'instantaneous_northward_turbulent_surface_stress', 'instantaneous_surface_sensible_heat_flux', 'k_index', 'lake_bottom_temperature', 'lake_cover', 'lake_depth', 'lake_ice_depth', 'lake_ice_temperature', 'lake_mix_layer_depth', 'lake_mix_layer_temperature', 'lake_shape_factor', 'lake_total_layer_temperature', 'land_sea_mask', 'large_scale_precipitation', 'large_scale_precipitation_fraction', 'large_scale_rain_rate', 'large_scale_snowfall', 'large_scale_snowfall_rate_water_equivalent', 'leaf_area_index_high_vegetation', 'leaf_area_index_low_vegetation', 'low_cloud_cover', 'low_vegetation_cover', 'maximum_2m_temperature_since_previous_post_processing', 'maximum_individual_wave_height', 'maximum_total_precipitation_rate_since_previous_post_processing', 'mean_boundary_layer_dissipation', 'mean_convective_precipitation_rate', 'mean_convective_snowfall_rate', 'mean_direction_of_total_swell', 'mean_direction_of_wind_waves', 'mean_eastward_gravity_wave_surface_stress', 'mean_eastward_turbulent_surface_stress', 'mean_evaporation_rate', 'mean_gravity_wave_dissipation', 'mean_large_scale_precipitation_fraction', 'mean_large_scale_precipitation_rate', 'mean_large_scale_snowfall_rate', 'mean_northward_gravity_wave_surface_stress', 'mean_northward_turbulent_surface_stress', 'mean_period_of_total_swell', 'mean_period_of_wind_waves', 'mean_potential_evaporation_rate', 'mean_runoff_rate', 'mean_sea_level_pressure', 'mean_snow_evaporation_rate', 'mean_snowfall_rate', 'mean_snowmelt_rate', 'mean_square_slope_of_waves', 'mean_sub_surface_runoff_rate', 'mean_surface_direct_short_wave_radiation_flux', 'mean_surface_direct_short_wave_radiation_flux_clear_sky', 'mean_surface_downward_long_wave_radiation_flux', 'mean_surface_downward_long_wave_radiation_flux_clear_sky', 'mean_surface_downward_short_wave_radiation_flux', 'mean_surface_downward_short_wave_radiation_flux_clear_sky', 'mean_surface_downward_uv_radiation_flux', 'mean_surface_latent_heat_flux', 'mean_surface_net_long_wave_radiation_flux', 'mean_surface_net_long_wave_radiation_flux_clear_sky', 'mean_surface_net_short_wave_radiation_flux', 'mean_surface_net_short_wave_radiation_flux_clear_sky', 'mean_surface_runoff_rate', 'mean_surface_sensible_heat_flux', 'mean_top_downward_short_wave_radiation_flux', 'mean_top_net_long_wave_radiation_flux', 'mean_top_net_long_wave_radiation_flux_clear_sky', 'mean_top_net_short_wave_radiation_flux', 'mean_top_net_short_wave_radiation_flux_clear_sky', 'mean_total_precipitation_rate', 'mean_vertical_gradient_of_refractivity_inside_trapping_layer', 'mean_vertically_integrated_moisture_divergence', 'mean_wave_direction', 'mean_wave_direction_of_first_swell_partition', 'mean_wave_direction_of_second_swell_partition', 'mean_wave_direction_of_third_swell_partition', 'mean_wave_period', 'mean_wave_period_based_on_first_moment', 'mean_wave_period_based_on_first_moment_for_swell', 'mean_wave_period_based_on_first_moment_for_wind_waves', 'mean_wave_period_based_on_second_moment_for_swell', 'mean_wave_period_based_on_second_moment_for_wind_waves', 'mean_wave_period_of_first_swell_partition', 'mean_wave_period_of_second_swell_partition', 'mean_wave_period_of_third_swell_partition', 'mean_zero_crossing_wave_period', 'medium_cloud_cover', 'minimum_2m_temperature_since_previous_post_processing', 'minimum_total_precipitation_rate_since_previous_post_processing', 'minimum_vertical_gradient_of_refractivity_inside_trapping_layer', 'model_bathymetry', 'near_ir_albedo_for_diffuse_radiation', 'near_ir_albedo_for_direct_radiation', 'normalized_energy_flux_into_ocean', 'normalized_energy_flux_into_waves', 'normalized_stress_into_ocean', 'northward_gravity_wave_surface_stress', 'northward_turbulent_surface_stress', 'ocean_surface_stress_equivalent_10m_neutral_wind_direction', 'ocean_surface_stress_equivalent_10m_neutral_wind_speed', 'peak_wave_period', 'period_corresponding_to_maximum_individual_wave_height', 'potential_evaporation', 'precipitation_type', 'runoff', 'sea_ice_cover', 'sea_surface_temperature', 'significant_height_of_combined_wind_waves_and_swell', 'significant_height_of_total_swell', 'significant_height_of_wind_waves', 'significant_wave_height_of_first_swell_partition', 'significant_wave_height_of_second_swell_partition', 'significant_wave_height_of_third_swell_partition', 'skin_reservoir_content', 'skin_temperature', 'slope_of_sub_gridscale_orography', 'snow_albedo', 'snow_density', 'snow_depth', 'snow_evaporation', 'snowfall', 'snowmelt', 'soil_temperature_level_1', 'soil_temperature_level_2', 'soil_temperature_level_3', 'soil_temperature_level_4', 'soil_type', 'standard_deviation_of_filtered_subgrid_orography', 'standard_deviation_of_orography', 'sub_surface_runoff', 'surface_latent_heat_flux', 'surface_net_solar_radiation', 'surface_net_solar_radiation_clear_sky', 'surface_net_thermal_radiation', 'surface_net_thermal_radiation_clear_sky', 'surface_pressure', 'surface_runoff', 'surface_sensible_heat_flux', 'surface_solar_radiation_downward_clear_sky', 'surface_solar_radiation_downwards', 'surface_thermal_radiation_downward_clear_sky', 'surface_thermal_radiation_downwards', 'temperature_of_snow_layer', 'toa_incident_solar_radiation', 'top_net_solar_radiation', 'top_net_solar_radiation_clear_sky', 'top_net_thermal_radiation', 'top_net_thermal_radiation_clear_sky', 'total_cloud_cover', 'total_column_cloud_ice_water', 'total_column_cloud_liquid_water', 'total_column_ozone', 'total_column_rain_water', 'total_column_snow_water', 'total_column_supercooled_liquid_water', 'total_column_water', 'total_column_water_vapour', 'total_precipitation', 'total_sky_direct_solar_radiation_at_surface', 'total_totals_index', 'trapping_layer_base_height', 'trapping_layer_top_height', 'type_of_high_vegetation', 'type_of_low_vegetation', 'u_component_stokes_drift', 'uv_visible_albedo_for_diffuse_radiation', 'uv_visible_albedo_for_direct_radiation', 'v_component_stokes_drift', 'vertical_integral_of_divergence_of_cloud_frozen_water_flux', 'vertical_integral_of_divergence_of_cloud_liquid_water_flux', 'vertical_integral_of_divergence_of_geopotential_flux', 'vertical_integral_of_divergence_of_kinetic_energy_flux', 'vertical_integral_of_divergence_of_mass_flux', 'vertical_integral_of_divergence_of_moisture_flux', 'vertical_integral_of_divergence_of_ozone_flux', 'vertical_integral_of_divergence_of_thermal_energy_flux', 'vertical_integral_of_divergence_of_total_energy_flux', 'vertical_integral_of_eastward_cloud_frozen_water_flux', 'vertical_integral_of_eastward_cloud_liquid_water_flux', 'vertical_integral_of_eastward_geopotential_flux', 'vertical_integral_of_eastward_heat_flux', 'vertical_integral_of_eastward_kinetic_energy_flux', 'vertical_integral_of_eastward_mass_flux', 'vertical_integral_of_eastward_ozone_flux', 'vertical_integral_of_eastward_total_energy_flux', 'vertical_integral_of_eastward_water_vapour_flux', 'vertical_integral_of_energy_conversion', 'vertical_integral_of_kinetic_energy', 'vertical_integral_of_mass_of_atmosphere', 'vertical_integral_of_mass_tendency', 'vertical_integral_of_northward_cloud_frozen_water_flux', 'vertical_integral_of_northward_cloud_liquid_water_flux', 'vertical_integral_of_northward_geopotential_flux', 'vertical_integral_of_northward_heat_flux', 'vertical_integral_of_northward_kinetic_energy_flux', 'vertical_integral_of_northward_mass_flux', 'vertical_integral_of_northward_ozone_flux', 'vertical_integral_of_northward_total_energy_flux', 'vertical_integral_of_northward_water_vapour_flux', 'vertical_integral_of_potential_and_internal_energy', 'vertical_integral_of_potential_internal_and_latent_energy', 'vertical_integral_of_temperature', 'vertical_integral_of_thermal_energy', 'vertical_integral_of_total_energy', 'vertically_integrated_moisture_divergence', 'volumetric_soil_water_layer_1', 'volumetric_soil_water_layer_2', 'volumetric_soil_water_layer_3', 'volumetric_soil_water_layer_4', 'wave_spectral_directional_width', 'wave_spectral_directional_width_for_swell', 'wave_spectral_directional_width_for_wind_waves', 'wave_spectral_kurtosis', 'wave_spectral_peakedness', 'wave_spectral_skewness', 'zero_degree_level'], FieldInfo(annotation=NoneType, required=True)],\n", + " 'year': typing.Annotated[typing.Literal['1940', '1941', '1942', '1943', '1944', '1945', '1946', '1947', '1948', '1949', '1950', '1951', '1952', '1953', '1954', '1955', '1956', '1957', '1958', '1959', '1960', '1961', '1962', '1963', '1964', '1965', '1966', '1967', '1968', '1969', '1970', '1971', '1972', '1973', '1974', '1975', '1976', '1977', '1978', '1979', '1980', '1981', '1982', '1983', '1984', '1985', '1986', '1987', '1988', '1989', '1990', '1991', '1992', '1993', '1994', '1995', '1996', '1997', '1998', '1999', '2000', '2001', '2002', '2003', '2004', '2005', '2006', '2007', '2008', '2009', '2010', '2011', '2012', '2013', '2014', '2015', '2016', '2017', '2018', '2019', '2020', '2021', '2022', '2023', '2024'], FieldInfo(annotation=NoneType, required=True)],\n", " 'end': typing.Annotated[typing.Optional[str], FieldInfo(annotation=NoneType, required=False, alias='completionTimeFromAscendingNode', alias_priority=2)],\n", " 'geom': typing.Annotated[typing.Optional[str], FieldInfo(annotation=NoneType, required=False, alias='geometry', alias_priority=2)],\n", + " 'productType': typing.Annotated[str, FieldInfo(annotation=NoneType, required=False, default='ERA5_SL')],\n", " 'id': typing.Annotated[typing.Optional[str], FieldInfo(annotation=NoneType, required=False)],\n", " 'start': typing.Annotated[typing.Optional[str], FieldInfo(annotation=NoneType, required=False, alias='startTimeFromAscendingNode', alias_priority=2)]}" ] }, - "execution_count": 6, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "dag.list_queryables(productType=\"ERA5_SL\", provider=\"cop_cds\", month=\"02\")" + "dag.list_queryables(\n", + " productType=\"ERA5_SL\", \n", + " provider=\"cop_cds\", \n", + " month=\"02\"\n", + ")" ] }, { @@ -2698,56 +2705,65 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "{'api_product_type': typing.Annotated[typing.Literal['gridded', 'hypsometry', 'vector'], FieldInfo(annotation=NoneType, required=False, default='gridded')],\n", - " 'variable': typing.Annotated[typing.Literal['glacier_area'], FieldInfo(annotation=NoneType, required=False, default='glacier_area')],\n", + "{'variable': typing.Annotated[typing.Literal['glacier_area'], FieldInfo(annotation=NoneType, required=False, default='glacier_area')],\n", + " 'api_product_type': typing.Annotated[typing.Literal['gridded', 'hypsometry', 'vector'], FieldInfo(annotation=NoneType, required=False, default='gridded')],\n", " 'version': typing.Annotated[typing.Literal['6_0'], FieldInfo(annotation=NoneType, required=False, default='6_0')],\n", - " 'productType': typing.Annotated[str, FieldInfo(annotation=NoneType, required=True)],\n", + " 'format': typing.Annotated[str, FieldInfo(annotation=NoneType, required=False, default='zip')],\n", " 'end': typing.Annotated[typing.Optional[str], FieldInfo(annotation=NoneType, required=False, alias='completionTimeFromAscendingNode', alias_priority=2)],\n", " 'geom': typing.Annotated[typing.Optional[str], FieldInfo(annotation=NoneType, required=False, alias='geometry', alias_priority=2)],\n", + " 'productType': typing.Annotated[str, FieldInfo(annotation=NoneType, required=False, default='GLACIERS_DIST_RANDOLPH')],\n", " 'id': typing.Annotated[typing.Optional[str], FieldInfo(annotation=NoneType, required=False)],\n", " 'start': typing.Annotated[typing.Optional[str], FieldInfo(annotation=NoneType, required=False, alias='startTimeFromAscendingNode', alias_priority=2)]}" ] }, - "execution_count": 7, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "dag.list_queryables(productType=\"GLACIERS_DIST_RANDOLPH\", provider=\"cop_cds\")" + "dag.list_queryables(\n", + " productType=\"GLACIERS_DIST_RANDOLPH\", \n", + " provider=\"cop_cds\"\n", + ")" ] }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "{'api_product_type': typing.Annotated[typing.Literal['gridded', 'hypsometry', 'vector'], FieldInfo(annotation=NoneType, required=False)],\n", - " 'variable': typing.Annotated[typing.Literal['glacier_area'], FieldInfo(annotation=NoneType, required=False, default='glacier_area')],\n", + "{'variable': typing.Annotated[typing.Literal['glacier_area'], FieldInfo(annotation=NoneType, required=False, default='glacier_area')],\n", + " 'api_product_type': typing.Annotated[typing.Literal['gridded', 'hypsometry', 'vector'], FieldInfo(annotation=NoneType, required=True)],\n", " 'version': typing.Annotated[typing.Literal['5_0', '6_0'], FieldInfo(annotation=NoneType, required=False, default='6_0')],\n", - " 'productType': typing.Annotated[str, FieldInfo(annotation=NoneType, required=True)],\n", + " 'format': typing.Annotated[str, FieldInfo(annotation=NoneType, required=False, default='zip')],\n", " 'end': typing.Annotated[typing.Optional[str], FieldInfo(annotation=NoneType, required=False, alias='completionTimeFromAscendingNode', alias_priority=2)],\n", " 'geom': typing.Annotated[typing.Optional[str], FieldInfo(annotation=NoneType, required=False, alias='geometry', alias_priority=2)],\n", + " 'productType': typing.Annotated[str, FieldInfo(annotation=NoneType, required=False, default='GLACIERS_DIST_RANDOLPH')],\n", " 'id': typing.Annotated[typing.Optional[str], FieldInfo(annotation=NoneType, required=False)],\n", " 'start': typing.Annotated[typing.Optional[str], FieldInfo(annotation=NoneType, required=False, alias='startTimeFromAscendingNode', alias_priority=2)]}" ] }, - "execution_count": 8, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "dag.list_queryables(productType=\"GLACIERS_DIST_RANDOLPH\", provider=\"cop_cds\", api_product_type=\"\")" + "dag.list_queryables(\n", + " productType=\"GLACIERS_DIST_RANDOLPH\", \n", + " provider=\"cop_cds\", \n", + " api_product_type=\"\"\n", + ")" ] }, { @@ -2774,7 +2790,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.10" + "version": "3.10.12" }, "widgets": { "application/vnd.jupyter.widget-state+json": { diff --git a/eodag/plugins/apis/base.py b/eodag/plugins/apis/base.py index a4262f3fd5..902e06e6b5 100644 --- a/eodag/plugins/apis/base.py +++ b/eodag/plugins/apis/base.py @@ -20,13 +20,13 @@ import logging from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple -from pydantic.fields import FieldInfo +from pydantic.fields import Field, FieldInfo if TYPE_CHECKING: from eodag.api.product import EOProduct from eodag.api.search_result import SearchResult from eodag.config import PluginConfig - from eodag.utils import DownloadedCallback, ProgressCallback, Annotated + from eodag.utils import DownloadedCallback, ProgressCallback from eodag.plugins.base import PluginTopic from eodag.utils import ( @@ -34,6 +34,7 @@ DEFAULT_DOWNLOAD_WAIT, DEFAULT_ITEMS_PER_PAGE, DEFAULT_PAGE, + Annotated, ) logger = logging.getLogger("eodag.apis.base") @@ -108,6 +109,23 @@ def discover_queryables( """ return None + def get_defaults_as_queryables( + self, product_type: str + ) -> Dict[str, Annotated[Any, FieldInfo]]: + """ + Return given product type defaut settings as queryables + + :param product_type: given product type + :type product_type: str + :returns: queryable parameters dict + :rtype: Dict[str, Annotated[Any, FieldInfo]] + """ + defaults = self.config.products.get(product_type, {}) + queryables = {} + for parameter, value in defaults.items(): + queryables[parameter] = Annotated[type(value), Field(default=value)] + return queryables + def download( self, product: EOProduct, diff --git a/eodag/plugins/apis/cds.py b/eodag/plugins/apis/cds.py index 4793b76ef9..c3f71127fe 100644 --- a/eodag/plugins/apis/cds.py +++ b/eodag/plugins/apis/cds.py @@ -76,8 +76,6 @@ logger = logging.getLogger("eodag.apis.cds") CDS_KNOWN_FORMATS = {"grib": "grib", "netcdf": "nc"} -# always available queryables (needed as not available in constraints) -CDS_ALLOWED_QUERYABLES = ["format"] class CdsApi(HTTPDownload, Api, BuildPostSearchResult): @@ -481,6 +479,12 @@ def discover_queryables( constraints = fetch_constraints(constraints_file_url, self) if not constraints: return {} + + # defaults + default_queryables = self.get_defaults_as_queryables(product_type) + # remove dataset from queryables + default_queryables.pop("dataset", None) + constraint_params: Dict[str, Dict[str, Set[Any]]] = {} if len(kwargs) == 0: # get values from constraints without additional filters @@ -493,11 +497,7 @@ def discover_queryables( constraint_params[key]["enum"] = set(constraint[key]) else: # get values from constraints with additional filters - constraints_input_params = { - k: v - for k, v in non_empty_kwargs.items() - if k not in CDS_ALLOWED_QUERYABLES - } + constraints_input_params = {k: v for k, v in non_empty_kwargs.items()} constraint_params = get_constraint_queryables_with_additional_params( constraints, constraints_input_params, self, product_type ) @@ -506,7 +506,9 @@ def discover_queryables( not_queryables = set() for constraint_param in constraint_params["not_available"]["enum"]: param = CommonQueryables.get_queryable_from_alias(constraint_param) - if param in CommonQueryables.model_fields: + if param in dict( + CommonQueryables.model_fields, **default_queryables + ): non_empty_kwargs.pop(constraint_param) else: not_queryables.add(constraint_param) @@ -535,4 +537,4 @@ def discover_queryables( field_definitions[param] = get_args(annotated_def) python_queryables = create_model("m", **field_definitions).model_fields - return model_fields_to_annotated(python_queryables) + return dict(default_queryables, **model_fields_to_annotated(python_queryables)) diff --git a/eodag/plugins/search/base.py b/eodag/plugins/search/base.py index 5ff3620748..b84d2e490b 100644 --- a/eodag/plugins/search/base.py +++ b/eodag/plugins/search/base.py @@ -20,7 +20,7 @@ import logging from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple -from pydantic.fields import FieldInfo +from pydantic.fields import Field, FieldInfo from eodag.api.product.metadata_mapping import ( DEFAULT_METADATA_MAPPING, @@ -31,13 +31,13 @@ DEFAULT_ITEMS_PER_PAGE, DEFAULT_PAGE, GENERIC_PRODUCT_TYPE, + Annotated, format_dict_items, ) if TYPE_CHECKING: from eodag.api.product import EOProduct from eodag.config import PluginConfig - from eodag.utils import Annotated logger = logging.getLogger("eodag.search.base") @@ -103,6 +103,23 @@ def discover_queryables( """ return None + def get_defaults_as_queryables( + self, product_type: str + ) -> Dict[str, Annotated[Any, FieldInfo]]: + """ + Return given product type defaut settings as queryables + + :param product_type: given product type + :type product_type: str + :returns: queryable parameters dict + :rtype: Dict[str, Annotated[Any, FieldInfo]] + """ + defaults = self.config.products.get(product_type, {}) + queryables = {} + for parameter, value in defaults.items(): + queryables[parameter] = Annotated[type(value), Field(default=value)] + return queryables + def map_product_type( self, product_type: Optional[str], **kwargs: Any ) -> Optional[str]: diff --git a/tests/units/test_apis_plugins.py b/tests/units/test_apis_plugins.py index 58652f8455..654ee6a65f 100644 --- a/tests/units/test_apis_plugins.py +++ b/tests/units/test_apis_plugins.py @@ -925,14 +925,14 @@ def test_plugins_apis_cds_discover_queryables(self, mock_requests_constraints): queryables = self.api_plugin.discover_queryables( productType="CAMS_EU_AIR_QUALITY_RE" ) - self.assertEqual(8, len(queryables)) + self.assertEqual(12, len(queryables)) self.assertIn("variable", queryables) # with additional param queryables = self.api_plugin.discover_queryables( productType="CAMS_EU_AIR_QUALITY_RE", variable="a", ) - self.assertEqual(8, len(queryables)) + self.assertEqual(12, len(queryables)) queryable = queryables.get("variable") self.assertEqual("a", queryable.__metadata__[0].get_default()) queryable = queryables.get("month") diff --git a/tests/units/test_http_server.py b/tests/units/test_http_server.py index b9613947c0..a7eb76027c 100644 --- a/tests/units/test_http_server.py +++ b/tests/units/test_http_server.py @@ -1205,7 +1205,7 @@ def test_product_type_queryables_from_constraints(self, mock_requests_constraint headers=USER_AGENT, timeout=5, ) - self.assertEqual(9, len(res["properties"])) + self.assertEqual(10, len(res["properties"])) self.assertIn("year", res["properties"]) self.assertIn("ids", res["properties"]) self.assertIn("geometry", res["properties"])