From 0f2cfebb789380be4ebba5132cbf24be3e1327ae Mon Sep 17 00:00:00 2001 From: Matt Fisher Date: Wed, 25 Sep 2024 17:51:13 -0600 Subject: [PATCH] Partially typecheck `APIformatting` module (#598) Co-authored-by: GitHub Action --- .../documentation/classes_dev_uml.svg | 762 ++++++++++-------- .../documentation/classes_user_uml.svg | 560 ++++++++----- .../documentation/packages_user_uml.svg | 188 +++-- icepyx/core/APIformatting.py | 79 +- icepyx/core/exceptions.py | 29 + pyproject.toml | 1 - 6 files changed, 966 insertions(+), 653 deletions(-) diff --git a/doc/source/user_guide/documentation/classes_dev_uml.svg b/doc/source/user_guide/documentation/classes_dev_uml.svg index 9084ffd70..1c75cf0b3 100644 --- a/doc/source/user_guide/documentation/classes_dev_uml.svg +++ b/doc/source/user_guide/documentation/classes_dev_uml.svg @@ -4,11 +4,11 @@ - - + + classes_dev_uml - + icepyx.quest.dataset_scripts.argo.Argo @@ -37,34 +37,34 @@ search_data(params, presRange, printURL): str - + icepyx.quest.dataset_scripts.dataset.DataSet - -DataSet - - -__init__ -(spatial_extent, date_range, start_time, end_time) -_fmt_coordinates -() -_fmt_timerange -() -_validate_inputs -() -download -() -save -(filepath) -search_data -() -visualize -() + +DataSet + + +__init__ +(spatial_extent, date_range, start_time, end_time) +_fmt_coordinates +() +_fmt_timerange +() +_validate_inputs +() +download +() +save +(filepath) +search_data +() +visualize +() - + icepyx.quest.dataset_scripts.argo.Argo->icepyx.quest.dataset_scripts.dataset.DataSet - - + + @@ -75,402 +75,528 @@ - + + +icepyx.core.types.CMRParamsWithBbox + +CMRParamsWithBbox + +bounding_box : str + + + + +icepyx.core.types.CMRParamsWithPolygon + +CMRParamsWithPolygon + +polygon : str + + + + + icepyx.core.exceptions.DeprecationError - -DeprecationError - - - + +DeprecationError + + + + + + +icepyx.core.types.EGIParamsSubsetBase + +EGIParamsSubsetBase + +Coverage : NotRequired[str] +format : NotRequired[str] +projection : NotRequired[str] +projection_parameters : NotRequired[str] +time : NotRequired[str] + + + + + +icepyx.core.types.EGIParamsSubsetBbox + +EGIParamsSubsetBbox + +bbox : NotRequired[str] + + + + + +icepyx.core.types.EGIParamsSubsetBbox->icepyx.core.types.EGIParamsSubsetBase + + + + + +icepyx.core.types.EGIParamsSubsetBoundingShape + +EGIParamsSubsetBoundingShape + +Boundingshape : NotRequired[str] + + + + + +icepyx.core.types.EGIParamsSubsetBoundingShape->icepyx.core.types.EGIParamsSubsetBase + + + + + +icepyx.core.types.EGIRequiredParamsBase + +EGIRequiredParamsBase + +page_num : int +page_size : int +short_name : Literal +version : str + + + + + +icepyx.core.types.EGIRequiredParamsDownload + +EGIRequiredParamsDownload + +client_string : Literal['icepyx'] +include_meta : Literal['Y', 'N'] +request_mode : Literal['sync', 'async', 'stream'] + + + + + +icepyx.core.types.EGIRequiredParamsDownload->icepyx.core.types.EGIRequiredParamsBase + + + + + +icepyx.core.types.EGIRequiredParamsSearch + +EGIRequiredParamsSearch + + + + + + +icepyx.core.types.EGIRequiredParamsSearch->icepyx.core.types.EGIRequiredParamsBase + + - + icepyx.core.auth.EarthdataAuthMixin - -EarthdataAuthMixin - -_auth : NoneType -_s3_initial_ts : NoneType, datetime -_s3login_credentials : NoneType -_session : NoneType -auth -s3login_credentials -session - -__init__(auth) -__str__() -earthdata_login(uid, email, s3token): None + +EarthdataAuthMixin + +_auth : NoneType +_s3_initial_ts : NoneType, datetime +_s3login_credentials : NoneType +_session : NoneType +auth +s3login_credentials +session + +__init__(auth) +__str__(): str +earthdata_login(uid, email, s3token): None - + icepyx.core.query.GenQuery - -GenQuery - -_spatial -_temporal -dates -end_time -spatial -spatial_extent -start_time -temporal - -__init__(spatial_extent, date_range, start_time, end_time) -__str__() + +GenQuery + +_spatial +_temporal +dates +end_time +spatial +spatial_extent +start_time +temporal + +__init__(spatial_extent, date_range, start_time, end_time) +__str__() - + icepyx.core.granules.Granules - -Granules - -avail : list -orderIDs : list - -__init__() -download(verbose, path, restart) -get_avail(CMRparams, reqparams, cloud) -place_order(CMRparams, reqparams, subsetparams, verbose, subset, geom_filepath) + +Granules + +avail : list +orderIDs : list + +__init__() +download(verbose, path, restart) +get_avail(CMRparams: CMRParams, reqparams: EGIRequiredParamsSearch, cloud: bool) +place_order(CMRparams: CMRParams, reqparams: EGIRequiredParamsDownload, subsetparams, verbose, subset, geom_filepath) icepyx.core.granules.Granules->icepyx.core.auth.EarthdataAuthMixin - - + + - + icepyx.core.query.Query - -Query - -CMRparams -_CMRparams -_about_product -_cust_options : dict -_cycles : list -_granules -_order_vars -_prod : NoneType, str -_readable_granule_name : list -_reqparams -_subsetparams : NoneType -_tracks : list -_version -cycles -dataset -granules -order_vars -product -product_version -reqparams -tracks - -__init__(product, spatial_extent, date_range, start_time, end_time, version, cycles, tracks, auth) -__str__() -avail_granules(ids, cycles, tracks, cloud) -download_granules(path, verbose, subset, restart) -latest_version() -order_granules(verbose, subset, email) -product_all_info() -product_summary_info() -show_custom_options(dictview) -subsetparams() -visualize_elevation() -visualize_spatial_extent() + +Query + +CMRparams +_CMRparams +_about_product +_cust_options : dict +_cycles : list +_granules +_order_vars +_prod : NoneType, str +_readable_granule_name : list +_reqparams +_subsetparams : Optional[apifmt.SubsetParameters] +_tracks : list +_version +cycles +dataset +granules +order_vars +product +product_version +reqparams +tracks + +__init__(product, spatial_extent, date_range, start_time, end_time, version, cycles, tracks, auth) +__str__() +avail_granules(ids, cycles, tracks, cloud) +download_granules(path, verbose, subset, restart) +latest_version() +order_granules(verbose, subset, email) +product_all_info() +product_summary_info() +show_custom_options(dictview) +subsetparams(): Union[EGIParamsSubset, dict[Never, Never]] +visualize_elevation() +visualize_spatial_extent() - + icepyx.core.granules.Granules->icepyx.core.query.Query - - -_granules + + +_granules - + icepyx.core.icesat2data.Icesat2Data - -Icesat2Data - - -__init__() + +Icesat2Data + + +__init__() - + icepyx.core.exceptions.NsidcQueryError - -NsidcQueryError - -errmsg -msgtxt : str - -__init__(errmsg, msgtxt) -__str__() + +NsidcQueryError + +errmsg +msgtxt : str + +__init__(errmsg, msgtxt) +__str__() - + icepyx.core.exceptions.QueryError - -QueryError - - - + +QueryError + + + icepyx.core.exceptions.NsidcQueryError->icepyx.core.exceptions.QueryError - - + + - + icepyx.core.APIformatting.Parameters - -Parameters - -_fmted_keys : NoneType, dict -_poss_keys : dict -_reqtype : NoneType, str -fmted_keys -partype -poss_keys - -__init__(partype, values, reqtype) -_check_valid_keys() -_get_possible_keys() -build_params() -check_req_values() -check_values() + +Parameters + +_fmted_keys : NoneType, dict +_reqtype : Optional[Literal['search', 'download']] +fmted_keys +partype : T +poss_keys + +__init__(partype: T, values: Optional[dict], reqtype: Optional[Literal['search', 'download']]) +_check_valid_keys(): None +build_params(): None +check_req_values(): bool +check_values(): bool - + icepyx.core.APIformatting.Parameters->icepyx.core.query.Query - - -_CMRparams + + +_CMRparams - + icepyx.core.APIformatting.Parameters->icepyx.core.query.Query - - -_reqparams + + +_reqparams - + icepyx.core.APIformatting.Parameters->icepyx.core.query.Query - - -_subsetparams + + +_subsetparams - + icepyx.core.APIformatting.Parameters->icepyx.core.query.Query - - -_subsetparams + + +_subsetparams icepyx.core.query.Query->icepyx.core.auth.EarthdataAuthMixin - - + + icepyx.core.query.Query->icepyx.core.query.GenQuery - - + + - + icepyx.quest.quest.Quest - -Quest - -datasets : dict - -__init__(spatial_extent, date_range, start_time, end_time, proj) -__str__() -add_argo(params, presRange): None -add_icesat2(product, start_time, end_time, version, cycles, tracks, files): None -download_all(path) -save_all(path) -search_all() + +Quest + +datasets : dict + +__init__(spatial_extent, date_range, start_time, end_time, proj) +__str__() +add_argo(params, presRange): None +add_icesat2(product, start_time, end_time, version, cycles, tracks, files): None +download_all(path) +save_all(path) +search_all() - + icepyx.quest.quest.Quest->icepyx.core.query.GenQuery - - + + - + icepyx.core.read.Read - -Read - -_filelist -_out_obj : Dataset -_product -_read_vars -filelist -is_s3 -product -vars - -__init__(data_source, glob_kwargs, out_obj_type, product, filename_pattern, catalog) -_add_vars_to_ds(is2ds, ds, grp_path, wanted_groups_tiered, wanted_dict) -_build_dataset_template(file) -_build_single_file_dataset(file, groups_list) -_combine_nested_vars(is2ds, ds, grp_path, wanted_dict) -_read_single_grp(file, grp_path) -load() + +Read + +_filelist +_out_obj : Dataset +_product +_read_vars +filelist +is_s3 +product +vars + +__init__(data_source, glob_kwargs, out_obj_type, product, filename_pattern, catalog) +_add_vars_to_ds(is2ds, ds, grp_path, wanted_groups_tiered, wanted_dict) +_build_dataset_template(file) +_build_single_file_dataset(file, groups_list) +_combine_nested_vars(is2ds, ds, grp_path, wanted_dict) +_read_single_grp(file, grp_path) +load() icepyx.core.read.Read->icepyx.core.auth.EarthdataAuthMixin - - + + - + icepyx.core.spatial.Spatial - -Spatial - -_ext_type : str -_gdf_spat : GeoDataFrame -_geom_file : NoneType -_spatial_ext -_xdateln -extent -extent_as_gdf -extent_file -extent_type - -__init__(spatial_extent) -__str__() -fmt_for_CMR() -fmt_for_EGI() + +Spatial + +_ext_type : str +_gdf_spat : GeoDataFrame +_geom_file : NoneType +_spatial_ext +_xdateln +extent +extent_as_gdf +extent_file +extent_type + +__init__(spatial_extent) +__str__() +fmt_for_CMR() +fmt_for_EGI() - + icepyx.core.spatial.Spatial->icepyx.core.query.GenQuery - - -_spatial + + +_spatial - + icepyx.core.spatial.Spatial->icepyx.core.query.GenQuery - - -_spatial + + +_spatial - + icepyx.core.temporal.Temporal - -Temporal - -_end : datetime -_start : datetime -end -start - -__init__(date_range, start_time, end_time) -__str__() + +Temporal + +_end : datetime +_start : datetime +end +start + +__init__(date_range, start_time, end_time) +__str__() - + icepyx.core.temporal.Temporal->icepyx.core.query.GenQuery - - -_temporal + + +_temporal - + icepyx.core.variables.Variables - -Variables - -_avail : NoneType, list -_path : NoneType -_product : NoneType, str -_version -path -product -version -wanted : NoneType, dict - -__init__(vartype, path, product, version, avail, wanted, auth) -_check_valid_lists(vgrp, allpaths, var_list, beam_list, keyword_list) -_get_combined_list(beam_list, keyword_list) -_get_sum_varlist(var_list, all_vars, defaults) -_iter_paths(sum_varlist, req_vars, vgrp, beam_list, keyword_list) -_iter_vars(sum_varlist, req_vars, vgrp) -append(defaults, var_list, beam_list, keyword_list) -avail(options, internal) -parse_var_list(varlist, tiered, tiered_vars) -remove(all, var_list, beam_list, keyword_list) + +Variables + +_avail : NoneType, list +_path : NoneType +_product : NoneType, str +_version +path +product +version +wanted : NoneType, dict + +__init__(vartype, path, product, version, avail, wanted, auth) +_check_valid_lists(vgrp, allpaths, var_list, beam_list, keyword_list) +_get_combined_list(beam_list, keyword_list) +_get_sum_varlist(var_list, all_vars, defaults) +_iter_paths(sum_varlist, req_vars, vgrp, beam_list, keyword_list) +_iter_vars(sum_varlist, req_vars, vgrp) +append(defaults, var_list, beam_list, keyword_list) +avail(options, internal) +parse_var_list(varlist, tiered, tiered_vars) +remove(all, var_list, beam_list, keyword_list) - + icepyx.core.variables.Variables->icepyx.core.auth.EarthdataAuthMixin - - + + - + icepyx.core.variables.Variables->icepyx.core.query.Query - - -_order_vars + + +_order_vars - + icepyx.core.variables.Variables->icepyx.core.query.Query - - -_order_vars + + +_order_vars - + icepyx.core.variables.Variables->icepyx.core.read.Read - - -_read_vars + + +_read_vars - + icepyx.core.variables.Variables->icepyx.core.read.Read - - -_read_vars + + +_read_vars - + icepyx.core.visualization.Visualize - -Visualize - -bbox : list -cycles : NoneType -date_range : NoneType -product : NoneType, str -tracks : NoneType - -__init__(query_obj, product, spatial_extent, date_range, cycles, tracks) -generate_OA_parameters(): list -grid_bbox(binsize): list -make_request(base_url, payload) -parallel_request_OA(): da.array -query_icesat2_filelist(): tuple -request_OA_data(paras): da.array -viz_elevation(): (hv.DynamicMap, hv.Layout) + +Visualize + +bbox : list +cycles : NoneType +date_range : NoneType +product : NoneType, str +tracks : NoneType + +__init__(query_obj, product, spatial_extent, date_range, cycles, tracks) +generate_OA_parameters(): list +grid_bbox(binsize): list +make_request(base_url, payload) +parallel_request_OA(): da.array +query_icesat2_filelist(): tuple +request_OA_data(paras): da.array +viz_elevation(): tuple[hv.DynamicMap, hv.Layout] + + + +icepyx.core.APIformatting._FmtedKeysDescriptor + +_FmtedKeysDescriptor + + +__get__(instance: 'Parameters[Literal["CMR"]]', owner: Any): CMRParams + + + +icepyx.core.APIformatting._FmtedKeysDescriptor->icepyx.core.APIformatting.Parameters + + +fmted_keys diff --git a/doc/source/user_guide/documentation/classes_user_uml.svg b/doc/source/user_guide/documentation/classes_user_uml.svg index 8b1273598..b4d2a024c 100644 --- a/doc/source/user_guide/documentation/classes_user_uml.svg +++ b/doc/source/user_guide/documentation/classes_user_uml.svg @@ -4,11 +4,11 @@ - - + + classes_user_uml - + icepyx.core.auth.AuthenticationError @@ -18,318 +18,446 @@ - + +icepyx.core.types.CMRParamsWithBbox + +CMRParamsWithBbox + +bounding_box : str + + + + + +icepyx.core.types.CMRParamsWithPolygon + +CMRParamsWithPolygon + +polygon : str + + + + + icepyx.core.exceptions.DeprecationError - -DeprecationError - - - + +DeprecationError + + + + + + +icepyx.core.types.EGIParamsSubsetBase + +EGIParamsSubsetBase + +Coverage : NotRequired[str] +format : NotRequired[str] +projection : NotRequired[str] +projection_parameters : NotRequired[str] +time : NotRequired[str] + + + + + +icepyx.core.types.EGIParamsSubsetBbox + +EGIParamsSubsetBbox + +bbox : NotRequired[str] + + + + + +icepyx.core.types.EGIParamsSubsetBbox->icepyx.core.types.EGIParamsSubsetBase + + + + + +icepyx.core.types.EGIParamsSubsetBoundingShape + +EGIParamsSubsetBoundingShape + +Boundingshape : NotRequired[str] + + + + + +icepyx.core.types.EGIParamsSubsetBoundingShape->icepyx.core.types.EGIParamsSubsetBase + + + + + +icepyx.core.types.EGIRequiredParamsBase + +EGIRequiredParamsBase + +page_num : int +page_size : int +short_name : Literal +version : str + + + + + +icepyx.core.types.EGIRequiredParamsDownload + +EGIRequiredParamsDownload + +client_string : Literal['icepyx'] +include_meta : Literal['Y', 'N'] +request_mode : Literal['sync', 'async', 'stream'] + + + + + +icepyx.core.types.EGIRequiredParamsDownload->icepyx.core.types.EGIRequiredParamsBase + + + + + +icepyx.core.types.EGIRequiredParamsSearch + +EGIRequiredParamsSearch + + + + + + +icepyx.core.types.EGIRequiredParamsSearch->icepyx.core.types.EGIRequiredParamsBase + + - + icepyx.core.auth.EarthdataAuthMixin - -EarthdataAuthMixin - -auth -s3login_credentials -session - -earthdata_login(uid, email, s3token): None + +EarthdataAuthMixin + +auth +s3login_credentials +session + +earthdata_login(uid, email, s3token): None - + icepyx.core.query.GenQuery - -GenQuery - -dates -end_time -spatial -spatial_extent -start_time -temporal - - + +GenQuery + +dates +end_time +spatial +spatial_extent +start_time +temporal + + - + icepyx.core.granules.Granules - -Granules - -avail : list -orderIDs : list - -download(verbose, path, restart) -get_avail(CMRparams, reqparams, cloud) -place_order(CMRparams, reqparams, subsetparams, verbose, subset, geom_filepath) + +Granules + +avail : list +orderIDs : list + +download(verbose, path, restart) +get_avail(CMRparams: CMRParams, reqparams: EGIRequiredParamsSearch, cloud: bool) +place_order(CMRparams: CMRParams, reqparams: EGIRequiredParamsDownload, subsetparams, verbose, subset, geom_filepath) icepyx.core.granules.Granules->icepyx.core.auth.EarthdataAuthMixin - - + + - + icepyx.core.query.Query - -Query - -CMRparams -cycles -dataset -granules -order_vars -product -product_version -reqparams -tracks - -avail_granules(ids, cycles, tracks, cloud) -download_granules(path, verbose, subset, restart) -latest_version() -order_granules(verbose, subset, email) -product_all_info() -product_summary_info() -show_custom_options(dictview) -subsetparams() -visualize_elevation() -visualize_spatial_extent() + +Query + +CMRparams +cycles +dataset +granules +order_vars +product +product_version +reqparams +tracks + +avail_granules(ids, cycles, tracks, cloud) +download_granules(path, verbose, subset, restart) +latest_version() +order_granules(verbose, subset, email) +product_all_info() +product_summary_info() +show_custom_options(dictview) +subsetparams(): Union[EGIParamsSubset, dict[Never, Never]] +visualize_elevation() +visualize_spatial_extent() - + icepyx.core.granules.Granules->icepyx.core.query.Query - - -_granules + + +_granules - + icepyx.core.icesat2data.Icesat2Data - -Icesat2Data - - - + +Icesat2Data + + + - + icepyx.core.exceptions.NsidcQueryError - -NsidcQueryError - -errmsg -msgtxt : str - - + +NsidcQueryError + +errmsg +msgtxt : str + + - + icepyx.core.exceptions.QueryError - -QueryError - - - + +QueryError + + + icepyx.core.exceptions.NsidcQueryError->icepyx.core.exceptions.QueryError - - + + - + icepyx.core.APIformatting.Parameters - -Parameters - -fmted_keys -partype -poss_keys - -build_params() -check_req_values() -check_values() + +Parameters + +fmted_keys +partype : T +poss_keys + +build_params(): None +check_req_values(): bool +check_values(): bool - + icepyx.core.APIformatting.Parameters->icepyx.core.query.Query - - -_CMRparams + + +_CMRparams - + icepyx.core.APIformatting.Parameters->icepyx.core.query.Query - - -_reqparams + + +_reqparams - + icepyx.core.APIformatting.Parameters->icepyx.core.query.Query - - -_subsetparams + + +_subsetparams - + icepyx.core.APIformatting.Parameters->icepyx.core.query.Query - - -_subsetparams + + +_subsetparams icepyx.core.query.Query->icepyx.core.auth.EarthdataAuthMixin - - + + icepyx.core.query.Query->icepyx.core.query.GenQuery - - + + - + icepyx.core.read.Read - -Read - -filelist -is_s3 -product -vars - -load() + +Read + +filelist +is_s3 +product +vars + +load() icepyx.core.read.Read->icepyx.core.auth.EarthdataAuthMixin - - + + - + icepyx.core.spatial.Spatial - -Spatial - -extent -extent_as_gdf -extent_file -extent_type - -fmt_for_CMR() -fmt_for_EGI() + +Spatial + +extent +extent_as_gdf +extent_file +extent_type + +fmt_for_CMR() +fmt_for_EGI() - + icepyx.core.spatial.Spatial->icepyx.core.query.GenQuery - - -_spatial + + +_spatial - + icepyx.core.spatial.Spatial->icepyx.core.query.GenQuery - - -_spatial + + +_spatial - + icepyx.core.temporal.Temporal - -Temporal - -end -start - - + +Temporal + +end +start + + - + icepyx.core.temporal.Temporal->icepyx.core.query.GenQuery - - -_temporal + + +_temporal - + icepyx.core.variables.Variables - -Variables - -path -product -version -wanted : NoneType, dict - -append(defaults, var_list, beam_list, keyword_list) -avail(options, internal) -parse_var_list(varlist, tiered, tiered_vars) -remove(all, var_list, beam_list, keyword_list) + +Variables + +path +product +version +wanted : NoneType, dict + +append(defaults, var_list, beam_list, keyword_list) +avail(options, internal) +parse_var_list(varlist, tiered, tiered_vars) +remove(all, var_list, beam_list, keyword_list) - + icepyx.core.variables.Variables->icepyx.core.auth.EarthdataAuthMixin - - + + - + icepyx.core.variables.Variables->icepyx.core.query.Query - - -_order_vars + + +_order_vars - + icepyx.core.variables.Variables->icepyx.core.query.Query - - -_order_vars + + +_order_vars - + icepyx.core.variables.Variables->icepyx.core.read.Read - - -_read_vars + + +_read_vars - + icepyx.core.variables.Variables->icepyx.core.read.Read - - -_read_vars + + +_read_vars - + icepyx.core.visualization.Visualize - -Visualize - -bbox : list -cycles : NoneType -date_range : NoneType -product : NoneType, str -tracks : NoneType - -generate_OA_parameters(): list -grid_bbox(binsize): list -make_request(base_url, payload) -parallel_request_OA(): da.array -query_icesat2_filelist(): tuple -request_OA_data(paras): da.array -viz_elevation(): (hv.DynamicMap, hv.Layout) + +Visualize + +bbox : list +cycles : NoneType +date_range : NoneType +product : NoneType, str +tracks : NoneType + +generate_OA_parameters(): list +grid_bbox(binsize): list +make_request(base_url, payload) +parallel_request_OA(): da.array +query_icesat2_filelist(): tuple +request_OA_data(paras): da.array +viz_elevation(): tuple[hv.DynamicMap, hv.Layout] + + + +icepyx.core.APIformatting._FmtedKeysDescriptor + +_FmtedKeysDescriptor + + + + + + +icepyx.core.APIformatting._FmtedKeysDescriptor->icepyx.core.APIformatting.Parameters + + +fmted_keys diff --git a/doc/source/user_guide/documentation/packages_user_uml.svg b/doc/source/user_guide/documentation/packages_user_uml.svg index 2cfe26a67..9d29c40d0 100644 --- a/doc/source/user_guide/documentation/packages_user_uml.svg +++ b/doc/source/user_guide/documentation/packages_user_uml.svg @@ -4,190 +4,214 @@ - + packages_user_uml - + icepyx.core - -icepyx.core + +icepyx.core icepyx.core.APIformatting - -icepyx.core.APIformatting + +icepyx.core.APIformatting + + + +icepyx.core.types + +icepyx.core.types + + + +icepyx.core.APIformatting->icepyx.core.types + + icepyx.core.auth - -icepyx.core.auth + +icepyx.core.auth icepyx.core.exceptions - -icepyx.core.exceptions + +icepyx.core.exceptions - + icepyx.core.auth->icepyx.core.exceptions - - + + icepyx.core.granules - -icepyx.core.granules + +icepyx.core.granules - + icepyx.core.granules->icepyx.core.auth - - + + + + + +icepyx.core.granules->icepyx.core.types + + - + icepyx.core.urls - -icepyx.core.urls + +icepyx.core.urls - + icepyx.core.granules->icepyx.core.urls - - + + icepyx.core.icesat2data - -icepyx.core.icesat2data + +icepyx.core.icesat2data - + icepyx.core.icesat2data->icepyx.core.exceptions - - + + icepyx.core.is2ref - -icepyx.core.is2ref + +icepyx.core.is2ref - + icepyx.core.is2ref->icepyx.core.urls - - + + icepyx.core.query - -icepyx.core.query + +icepyx.core.query - + icepyx.core.query->icepyx.core.auth - - + + - + icepyx.core.query->icepyx.core.exceptions - - + + - + icepyx.core.query->icepyx.core.granules - - + + + + + +icepyx.core.query->icepyx.core.types + + - + icepyx.core.variables - -icepyx.core.variables + +icepyx.core.variables - + icepyx.core.query->icepyx.core.variables - - + + - + icepyx.core.visualization - -icepyx.core.visualization + +icepyx.core.visualization - + icepyx.core.query->icepyx.core.visualization - - + + icepyx.core.read - -icepyx.core.read + +icepyx.core.read - + icepyx.core.read->icepyx.core.auth - - + + - + icepyx.core.read->icepyx.core.exceptions - - + + - + icepyx.core.read->icepyx.core.variables - - + + icepyx.core.spatial - -icepyx.core.spatial + +icepyx.core.spatial icepyx.core.temporal - -icepyx.core.temporal + +icepyx.core.temporal - + icepyx.core.validate_inputs - -icepyx.core.validate_inputs + +icepyx.core.validate_inputs - + icepyx.core.variables->icepyx.core.auth - - + + - + icepyx.core.variables->icepyx.core.exceptions - - + + diff --git a/icepyx/core/APIformatting.py b/icepyx/core/APIformatting.py index 1c225d2ef..7ef1e7e7b 100644 --- a/icepyx/core/APIformatting.py +++ b/icepyx/core/APIformatting.py @@ -1,8 +1,9 @@ """Generate and format information for submitting to API (CMR and NSIDC).""" import datetime as dt -from typing import Any, Generic, Literal, TypeVar, Union, overload +from typing import Any, Generic, Literal, Optional, TypeVar, Union, overload +from icepyx.core.exceptions import ExhaustiveTypeGuardException, TypeGuardException from icepyx.core.types import ( CMRParams, EGIParamsSubset, @@ -36,10 +37,6 @@ def _fmt_temporal(start, end, key): assert isinstance(start, dt.datetime) assert isinstance(end, dt.datetime) - assert key in [ - "time", - "temporal", - ], "An invalid time key was submitted for formatting." if key == "temporal": fmt_timerange = ( @@ -53,6 +50,8 @@ def _fmt_temporal(start, end, key): + "," + end.strftime("%Y-%m-%dT%H:%M:%S") ) + else: + raise ValueError("An invalid time key was submitted for formatting.") return {key: fmt_timerange} @@ -231,7 +230,7 @@ def __get__( Returns the dictionary of formatted keys associated with the parameter object. """ - return instance._fmted_keys + return instance._fmted_keys # pyright: ignore[reportReturnType] # ---------------------------------------------------------------------- @@ -257,13 +256,16 @@ class Parameters(Generic[T]): on the type of query. Must be one of ['search','download'] """ + partype: T + _reqtype: Optional[Literal["search", "download"]] fmted_keys = _FmtedKeysDescriptor() + # _fmted_keys: Union[CMRParams, EGISpecificRequiredParams, EGIParamsSubset] def __init__( self, partype: T, - values=None, - reqtype=None, + values: Optional[dict] = None, + reqtype: Optional[Literal["search", "download"]] = None, ): assert partype in [ "CMR", @@ -282,31 +284,14 @@ def __init__( self._fmted_keys = values if values is not None else {} @property - def poss_keys(self): + def poss_keys(self) -> dict[str, list[str]]: """ Returns a list of possible input keys for the given parameter object. Possible input keys depend on the parameter type (partype). """ - if not hasattr(self, "_poss_keys"): - self._get_possible_keys() - - return self._poss_keys - - # @property - # def wanted_keys(self): - # if not hasattr(_wanted): - # self._wanted = [] - - # return self._wanted - - def _get_possible_keys(self) -> dict[str, list[str]]: - """ - Use the parameter type to get a list of possible parameter keys. - """ - if self.partype == "CMR": - self._poss_keys = { + return { "spatial": ["bounding_box", "polygon"], "optional": [ "temporal", @@ -316,7 +301,7 @@ def _get_possible_keys(self) -> dict[str, list[str]]: ], } elif self.partype == "required": - self._poss_keys = { + return { "search": ["short_name", "version", "page_size"], "download": [ "short_name", @@ -331,7 +316,7 @@ def _get_possible_keys(self) -> dict[str, list[str]]: ], } elif self.partype == "subset": - self._poss_keys = { + return { "spatial": ["bbox", "Boundingshape"], "optional": [ "time", @@ -341,8 +326,17 @@ def _get_possible_keys(self) -> dict[str, list[str]]: "Coverage", ], } + else: + raise ExhaustiveTypeGuardException + + # @property + # def wanted_keys(self): + # if not hasattr(_wanted): + # self._wanted = [] - def _check_valid_keys(self): + # return self._wanted + + def _check_valid_keys(self) -> None: """ Checks that any keys passed in with values are valid keys. """ @@ -352,13 +346,13 @@ def _check_valid_keys(self): val_list = list({val for lis in self.poss_keys.values() for val in lis}) - for key in self.fmted_keys: + for key in self.fmted_keys: # pyright: ignore[reportAttributeAccessIssue] assert key in val_list, ( "An invalid key (" + key + ") was passed. Please remove it using `del`" ) # DevNote: can check_req_values and check_values be combined? - def check_req_values(self): + def check_req_values(self) -> bool: """ Check that all of the required keys have values, if the key was passed in with the values parameter. @@ -367,17 +361,22 @@ def check_req_values(self): assert ( self.partype == "required" ), "You cannot call this function for your parameter type" + + if not self._reqtype: + raise TypeGuardException + reqkeys = self.poss_keys[self._reqtype] - if all(keys in self.fmted_keys for keys in reqkeys): + if all(keys in self.fmted_keys for keys in reqkeys): # pyright: ignore[reportAttributeAccessIssue] assert all( - self.fmted_keys.get(key, -9999) != -9999 for key in reqkeys + self.fmted_keys.get(key, -9999) != -9999 # pyright: ignore[reportAttributeAccessIssue] + for key in reqkeys ), "One of your formatted parameters is missing a value" return True else: return False - def check_values(self): + def check_values(self) -> bool: """ Check that the non-required keys have values, if the key was passed in with the values parameter. @@ -391,7 +390,8 @@ def check_values(self): # not the most robust check, but better than nothing... if any(keys in self._fmted_keys for keys in spatial_keys): assert any( - self.fmted_keys.get(key, -9999) != -9999 for key in spatial_keys + self.fmted_keys.get(key, -9999) != -9999 # pyright: ignore[reportAttributeAccessIssue] + for key in spatial_keys ), "One of your formatted parameters is missing a value" return True else: @@ -427,6 +427,9 @@ def build_params(self, **kwargs) -> None: self._check_valid_keys() if self.partype == "required": + if not self._reqtype: + raise TypeGuardException + if self.check_req_values() and kwargs == {}: pass else: @@ -484,6 +487,7 @@ def build_params(self, **kwargs) -> None: if any(keys in self._fmted_keys for keys in spatial_keys): pass else: + k = None if self.partype == "CMR": k = kwargs["extent_type"] elif self.partype == "subset": @@ -492,6 +496,9 @@ def build_params(self, **kwargs) -> None: elif kwargs["extent_type"] == "polygon": k = "Boundingshape" + if not k: + raise TypeGuardException + self._fmted_keys.update({k: kwargs["spatial_extent"]}) diff --git a/icepyx/core/exceptions.py b/icepyx/core/exceptions.py index 94bbea768..085fed8c9 100644 --- a/icepyx/core/exceptions.py +++ b/icepyx/core/exceptions.py @@ -1,3 +1,10 @@ +ISSUE_REPORTING_INSTRUCTIONS = ( + "If you are a user seeing this message, the developers of this software have made a" + " mistake! Please report the full error traceback in the icepyx GitHub repository:" + " " +) + + class DeprecationError(Exception): """ Class raised for use of functionality that is no longer supported by icepyx. @@ -24,3 +31,25 @@ def __init__( def __str__(self): return f"{self.msgtxt}: {self.errmsg}" + + +class TypeGuardException(Exception): + """ + Should never be raised at runtime. + + Used in cases where a runtime check is not desired, but we want to add a "type guard" + (https://github.com/microsoft/pyright/blob/main/docs/type-concepts-advanced.md#type-guards) + to give the type checker more information. + """ + + def __str__(self): + return ISSUE_REPORTING_INSTRUCTIONS + + +class ExhaustiveTypeGuardException(TypeGuardException): + """ + Should never be raised at runtime. + + Used exclusively in cases where the typechecker needs a typeguard to tell it that a + check is exhaustive. + """ diff --git a/pyproject.toml b/pyproject.toml index 564f53976..fb4907d35 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -140,7 +140,6 @@ exclude = [ # DevGoal: Remove all ignores ignore = [ "icepyx/quest/*", - "icepyx/core/APIformatting.py", "icepyx/core/auth.py", "icepyx/core/is2ref.py", "icepyx/core/read.py",