hdx-python-api 6.7.7__py3-none-any.whl → 6.7.9__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
hdx/api/_version.py CHANGED
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '6.7.7'
22
- __version_tuple__ = version_tuple = (6, 7, 7)
21
+ __version__ = version = '6.7.9'
22
+ __version_tuple__ = version_tuple = (6, 7, 9)
23
23
 
24
24
  __commit_id__ = commit_id = None
hdx/api/configuration.py CHANGED
@@ -200,7 +200,7 @@ class Configuration(UserDict):
200
200
  if hdx_read_only is None:
201
201
  hdx_read_only = False
202
202
  self.hdx_read_only = hdx_read_only
203
- logger.info(f"Read only access to HDX: {str(self.hdx_read_only)}")
203
+ logger.info(f"Read only access to HDX: {self.hdx_read_only!s}")
204
204
 
205
205
  if self.hdx_site == "hdx_custom_site":
206
206
  hdx_key = None
hdx/api/locations.py CHANGED
File without changes
@@ -63,7 +63,7 @@ class DateHelper:
63
63
  def get_time_period_info(
64
64
  hdx_time_period: str,
65
65
  date_format: str | None = None,
66
- today: datetime = now_utc(),
66
+ today: datetime | None = None,
67
67
  ) -> dict:
68
68
  """Get time period as datetimes and strings in specified format.
69
69
  If no format is supplied, the ISO 8601 format is used. Returns a
@@ -80,6 +80,8 @@ class DateHelper:
80
80
  Returns:
81
81
  Dictionary of date information
82
82
  """
83
+ if today is None:
84
+ today = now_utc()
83
85
  result = {}
84
86
  if hdx_time_period:
85
87
  if hdx_time_period[0] == "[" and hdx_time_period[-1] == "]":
File without changes
@@ -1,6 +1,7 @@
1
1
  import logging
2
2
  from collections.abc import Sequence
3
3
  from os import getenv
4
+ from types import TracebackType
4
5
  from typing import Any
5
6
 
6
7
  from hdx.utilities.dictandlist import dict_of_sets_add
@@ -32,7 +33,7 @@ class HDXErrorHandler(ErrorHandler):
32
33
  ):
33
34
  super().__init__(should_exit_on_error)
34
35
  if write_to_hdx is None:
35
- write_to_hdx = getenv("ERR_TO_HDX", True)
36
+ write_to_hdx = getenv("ERR_TO_HDX", "True")
36
37
  if write_to_hdx in (False, 0, "false", "False", "FALSE", "N", "n", ""):
37
38
  self._write_to_hdx = False
38
39
  logger.info("Errors won't be written to HDX")
@@ -210,7 +211,12 @@ class HDXErrorHandler(ErrorHandler):
210
211
  if self._write_to_hdx:
211
212
  self.write_errors_to_hdx()
212
213
 
213
- def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None:
214
+ def __exit__(
215
+ self,
216
+ exc_type: type[BaseException] | None,
217
+ exc_value: BaseException | None,
218
+ traceback: TracebackType | None,
219
+ ) -> None:
214
220
  if self._write_to_hdx:
215
221
  self.write_errors_to_hdx()
216
222
  super().__exit__(exc_type, exc_value, traceback)
hdx/data/__init__.py CHANGED
File without changes
hdx/data/dataset.py CHANGED
@@ -10,6 +10,7 @@ from pathlib import Path
10
10
  from typing import (
11
11
  TYPE_CHECKING,
12
12
  Any,
13
+ ClassVar,
13
14
  Optional,
14
15
  Union,
15
16
  )
@@ -19,7 +20,6 @@ from hdx.utilities.base_downloader import BaseDownload
19
20
  from hdx.utilities.dateparse import (
20
21
  default_date,
21
22
  default_enddate,
22
- now_utc,
23
23
  now_utc_notz,
24
24
  parse_date,
25
25
  parse_date_range,
@@ -34,12 +34,11 @@ import hdx.api.utilities.url_utils
34
34
  import hdx.data.organization as org_module
35
35
  import hdx.data.resource as res_module
36
36
  import hdx.data.showcase as sc_module
37
- import hdx.data.user as user
38
- import hdx.data.vocabulary as vocabulary
39
37
  from hdx.api.configuration import Configuration
40
38
  from hdx.api.locations import Locations
41
39
  from hdx.api.utilities.date_helper import DateHelper
42
40
  from hdx.api.utilities.filestore_helper import FilestoreHelper
41
+ from hdx.data import user, vocabulary
43
42
  from hdx.data.activity import Activity
44
43
  from hdx.data.hdxobject import HDXError, HDXObject
45
44
  from hdx.data.resource_matcher import ResourceMatcher
@@ -67,7 +66,7 @@ class Dataset(HDXObject):
67
66
 
68
67
  max_attempts = 5
69
68
  max_int = sys.maxsize
70
- update_frequencies = {
69
+ update_frequencies: ClassVar[dict[str, str]] = {
71
70
  "-2": "As needed",
72
71
  "-1": "Never",
73
72
  "0": "Live",
@@ -224,7 +223,7 @@ class Dataset(HDXObject):
224
223
  session = hdx.api.utilities.url_utils.get_ckan_ready_session(
225
224
  self.configuration
226
225
  )
227
- for resource in dataset_dict.get("resources", tuple()):
226
+ for resource in dataset_dict.get("resources", ()):
228
227
  resource["url"] = hdx.api.utilities.url_utils.follow_url(
229
228
  resource["url"], session=session
230
229
  )
@@ -295,11 +294,10 @@ class Dataset(HDXObject):
295
294
  The resource that was added after matching with any existing resource
296
295
  """
297
296
  resource = self._get_resource_from_obj(resource)
298
- if "package_id" in resource:
299
- if not ignore_datasetid:
300
- raise HDXError(
301
- f"Resource {resource['name']} being added already has a dataset id!"
302
- )
297
+ if "package_id" in resource and not ignore_datasetid:
298
+ raise HDXError(
299
+ f"Resource {resource['name']} being added already has a dataset id!"
300
+ )
303
301
  resource.check_both_url_filetoupload()
304
302
  resource_index = ResourceMatcher.match_resource_list(self._resources, resource)
305
303
  if resource_index is None:
@@ -331,11 +329,10 @@ class Dataset(HDXObject):
331
329
  resource_objects = []
332
330
  for resource in resources:
333
331
  resource = self._get_resource_from_obj(resource)
334
- if "package_id" in resource:
335
- if not ignore_datasetid:
336
- raise HDXError(
337
- f"Resource {resource['name']} being added already has a dataset id!"
338
- )
332
+ if "package_id" in resource and not ignore_datasetid:
333
+ raise HDXError(
334
+ f"Resource {resource['name']} being added already has a dataset id!"
335
+ )
339
336
  resource.check_both_url_filetoupload()
340
337
  resource_objects.append(resource)
341
338
  (
@@ -371,9 +368,8 @@ class Dataset(HDXObject):
371
368
  Returns:
372
369
  True if resource removed or False if not
373
370
  """
374
- if isinstance(resource, str):
375
- if is_valid_uuid(resource) is False:
376
- raise HDXError(f"{resource} is not a valid resource id!")
371
+ if isinstance(resource, str) and is_valid_uuid(resource) is False:
372
+ raise HDXError(f"{resource} is not a valid resource id!")
377
373
  return self._remove_hdxobject(self._resources, resource, delete=delete)
378
374
 
379
375
  def get_resources(self) -> list["Resource"]:
@@ -593,8 +589,8 @@ class Dataset(HDXObject):
593
589
  def revise(
594
590
  match: dict[str, Any],
595
591
  filter: Sequence[str] = (),
596
- update: dict[str, Any] = {},
597
- files_to_upload: dict[str, str] = {},
592
+ update: dict[str, Any] | None = None,
593
+ files_to_upload: dict[str, str] | None = None,
598
594
  configuration: Configuration | None = None,
599
595
  **kwargs: Any,
600
596
  ) -> "Dataset":
@@ -611,6 +607,10 @@ class Dataset(HDXObject):
611
607
  Returns:
612
608
  Dataset object
613
609
  """
610
+ if files_to_upload is None:
611
+ files_to_upload = {}
612
+ if update is None:
613
+ update = {}
614
614
  separators = (",", ":")
615
615
  data = {"match": json.dumps(match, separators=separators)}
616
616
  if filter:
@@ -667,21 +667,90 @@ class Dataset(HDXObject):
667
667
  if "batch_mode" not in kwargs:
668
668
  kwargs["batch_mode"] = "DONT_GROUP"
669
669
 
670
+ def _merge_list_fields(self, dataset_data_to_update: dict) -> list[str]:
671
+ """Merges each non-resource list in dataset_data_to_update with the
672
+ existing list of the same key (see _merge_list) in place.
673
+
674
+ Args:
675
+ dataset_data_to_update: Dataset data to be updated
676
+
677
+ Returns:
678
+ Keys whose merged list differs from the existing one
679
+ """
680
+ changed_keys = []
681
+ for key, value in dataset_data_to_update.items():
682
+ if (
683
+ key == "resources"
684
+ or not isinstance(value, list)
685
+ or key not in self._old_data
686
+ ):
687
+ continue
688
+ orig_list = self._old_data[key]
689
+ if not isinstance(orig_list, list):
690
+ orig_list = []
691
+ merged_list = self._merge_list(orig_list, value)
692
+ dataset_data_to_update[key] = merged_list
693
+ if merged_list != orig_list:
694
+ changed_keys.append(key)
695
+ return changed_keys
696
+
697
+ @staticmethod
698
+ def _merge_list(orig_list: list, new_list: list) -> list:
699
+ """Merges each dict in new_list that has an id or name with the dict in
700
+ orig_list with the same id (or failing that, name) so that fields not
701
+ given in new_list are kept. Other elements of new_list are kept as is.
702
+ Elements of orig_list that are not matched are dropped.
703
+
704
+ Args:
705
+ orig_list: Existing list
706
+ new_list: Updated list
707
+
708
+ Returns:
709
+ Merged list
710
+ """
711
+ merged_list = []
712
+ for new_value in new_list:
713
+ if not isinstance(new_value, dict):
714
+ merged_list.append(new_value)
715
+ continue
716
+ match = {}
717
+ for field in ("id", "name"):
718
+ field_value = new_value.get(field)
719
+ if not field_value:
720
+ continue
721
+ match = next(
722
+ (
723
+ orig_value
724
+ for orig_value in orig_list
725
+ if isinstance(orig_value, dict)
726
+ and orig_value.get(field) == field_value
727
+ ),
728
+ {},
729
+ )
730
+ if match:
731
+ break
732
+ merged_list.append(match | new_value)
733
+ return merged_list
734
+
670
735
  def _revise_filter(
671
736
  self,
672
- dataset_data_to_update: dict,
673
737
  keys_to_delete: Sequence[str],
674
738
  resources_to_delete: Sequence[int],
675
- ):
739
+ changed_list_keys: Sequence[str],
740
+ ) -> list[str]:
676
741
  """Returns the revise filter parameter adding to it any keys in the
677
- dataset metadata and resources that are specified to be deleted. Also compare
678
- lists in original and updated metadata to see if any have had elements
679
- removed in which case these should be added to the filter
742
+ dataset metadata and resources that are specified to be deleted. Keys
743
+ of changed lists are also added so that package_revise replaces those
744
+ lists rather than merging them by position (which keeps the existing
745
+ elements' ids eg. for groups).
680
746
 
681
747
  Args:
682
- dataset_data_to_update: Dataset data to be updated
683
748
  keys_to_delete: List of top level metadata keys to delete
684
749
  resources_to_delete: List of indexes of resources to delete
750
+ changed_list_keys: Keys of lists that differ from the existing ones
751
+
752
+ Returns:
753
+ Revise filter
685
754
  """
686
755
  revise_filter = []
687
756
  for key in keys_to_delete:
@@ -689,46 +758,9 @@ class Dataset(HDXObject):
689
758
  if not self.is_requestable():
690
759
  for resource_index in resources_to_delete:
691
760
  revise_filter.append(f"-resources__{resource_index}")
692
- for key, value in dataset_data_to_update.items():
693
- if not isinstance(value, list):
694
- continue
695
- if key not in self._old_data:
696
- continue
697
- orig_list = self._old_data[key]
698
- elements_to_remove = []
699
- for i, orig_value in enumerate(orig_list):
700
- if isinstance(orig_value, dict) and any(
701
- x in orig_value for x in ("id", "name")
702
- ):
703
- # Where lists have an id or name, we use one of those to
704
- # match elements and work out what needs to be deleted
705
- # ie. any elements in the original list that don't exist
706
- # in the updated list
707
- el_id = orig_value.get("id")
708
- el_name = orig_value.get("name")
709
- present = False
710
- for value_dict in value:
711
- if el_id and "id" in value_dict and value_dict["id"] == el_id:
712
- present = True
713
- break
714
- if (
715
- el_name
716
- and "name" in value_dict
717
- and value_dict["name"] == el_name
718
- ):
719
- present = True
720
- break
721
- if not present:
722
- elements_to_remove.append(i)
723
- elif orig_value not in value:
724
- # Otherwise we do a simple exact match of list elements
725
- # and delete any elements that are in the original list but
726
- # not in the updated list
727
- elements_to_remove.append(i)
728
- for element_index in reversed(elements_to_remove):
729
- del orig_list[element_index]
730
- if element_index == len(orig_list):
731
- revise_filter.append(f"-{key}__{element_index}")
761
+ for key in changed_list_keys:
762
+ if key not in keys_to_delete:
763
+ revise_filter.append(f"-{key}")
732
764
  return revise_filter
733
765
 
734
766
  def _revise_files_to_upload_resource_deletions(
@@ -750,11 +782,11 @@ class Dataset(HDXObject):
750
782
  for resource_index in resources_to_delete:
751
783
  del resources_to_update[resource_index]
752
784
  new_fsresources = {}
753
- for index in filestore_resources:
785
+ for index, fsresource in filestore_resources.items():
754
786
  if index > resource_index:
755
- new_fsresources[index - 1] = filestore_resources[index]
787
+ new_fsresources[index - 1] = fsresource
756
788
  else:
757
- new_fsresources[index] = filestore_resources[index]
789
+ new_fsresources[index] = fsresource
758
790
  filestore_resources = new_fsresources
759
791
  for (
760
792
  resource_index,
@@ -806,8 +838,9 @@ class Dataset(HDXObject):
806
838
  ): # Whether or not CKAN should perform validation steps (checking fields present)
807
839
  dataset_data_to_update["skip_validation"] = kwargs["skip_validation"]
808
840
  dataset_data_to_update["state"] = "active"
841
+ changed_list_keys = self._merge_list_fields(dataset_data_to_update)
809
842
  revise_filter = self._revise_filter(
810
- dataset_data_to_update, keys_to_delete, resources_to_delete
843
+ keys_to_delete, resources_to_delete, changed_list_keys
811
844
  )
812
845
  files_to_upload = self._revise_files_to_upload_resource_deletions(
813
846
  resources_to_update,
@@ -1048,8 +1081,8 @@ class Dataset(HDXObject):
1048
1081
  **kwargs,
1049
1082
  )
1050
1083
  keep_crisis_tags = kwargs.get("keep_crisis_tags", True)
1051
- if keep_crisis_tags:
1052
- old_tags = self._old_data.get("tags", [])
1084
+ if keep_crisis_tags and "tags" in self._old_data:
1085
+ old_tags = self._old_data["tags"]
1053
1086
  for tag in self.data.get("tags", []):
1054
1087
  tag_name = tag["name"]
1055
1088
  if tag_name[:7] != "crisis-":
@@ -1061,7 +1094,6 @@ class Dataset(HDXObject):
1061
1094
  break
1062
1095
  if not found:
1063
1096
  old_tags.append(tag)
1064
- self._old_data["tags"] = old_tags
1065
1097
  self._prepare_hdx_call(self._old_data, kwargs)
1066
1098
  revise_call = self._revise_dataset(
1067
1099
  allow_no_resources,
@@ -1182,15 +1214,13 @@ class Dataset(HDXObject):
1182
1214
  """
1183
1215
  self.check_resources_url_filetoupload()
1184
1216
  loadedid = self.data.get("id")
1185
- if loadedid is not None:
1186
- if not self._dataset_load_from_hdx(loadedid):
1187
- logger.warning(f"Failed to load dataset with id {loadedid}")
1188
- loadedid = None
1217
+ if loadedid is not None and not self._dataset_load_from_hdx(loadedid):
1218
+ logger.warning(f"Failed to load dataset with id {loadedid}")
1219
+ loadedid = None
1189
1220
  if not loadedid:
1190
1221
  loadedid = self.data.get("name")
1191
- if loadedid is not None:
1192
- if not self._dataset_load_from_hdx(loadedid):
1193
- loadedid = None
1222
+ if loadedid is not None and not self._dataset_load_from_hdx(loadedid):
1223
+ loadedid = None
1194
1224
  if loadedid:
1195
1225
  statuses, _ = self._dataset_hdx_update(
1196
1226
  allow_no_resources=allow_no_resources,
@@ -1433,8 +1463,7 @@ class Dataset(HDXObject):
1433
1463
  """
1434
1464
  resources = []
1435
1465
  for dataset in datasets:
1436
- for resource in dataset.get_resources():
1437
- resources.append(resource)
1466
+ resources.extend(dataset.get_resources())
1438
1467
  return resources
1439
1468
 
1440
1469
  def get_activities(self, all_pages: bool = False, **kwargs: Any) -> list[Activity]:
@@ -1479,7 +1508,7 @@ class Dataset(HDXObject):
1479
1508
  def get_time_period(
1480
1509
  self,
1481
1510
  date_format: str | None = None,
1482
- today: datetime = now_utc(),
1511
+ today: datetime | None = None,
1483
1512
  ) -> dict:
1484
1513
  """Get dataset date as datetimes and strings in specified format. If no format is supplied, the ISO 8601
1485
1514
  format is used. Returns a dictionary containing keys startdate (start date as datetime), enddate (end
@@ -1595,7 +1624,7 @@ class Dataset(HDXObject):
1595
1624
  int(update_frequency)
1596
1625
  except ValueError:
1597
1626
  update_frequency = Dataset.transform_update_frequency(update_frequency)
1598
- if update_frequency not in Dataset.update_frequencies.keys():
1627
+ if update_frequency not in Dataset.update_frequencies:
1599
1628
  raise HDXError("Invalid update frequency supplied!")
1600
1629
  self.data["data_update_frequency"] = update_frequency
1601
1630
 
@@ -1748,7 +1777,7 @@ class Dataset(HDXObject):
1748
1777
  Returns:
1749
1778
  True if country added or False if country already present
1750
1779
  """
1751
- iso3, match = Country.get_iso3_country_code_fuzzy(country, use_live=use_live)
1780
+ iso3, _match = Country.get_iso3_country_code_fuzzy(country, use_live=use_live)
1752
1781
  if iso3 is None:
1753
1782
  raise HDXError(f"Country: {country} - cannot find iso3 code!")
1754
1783
  return self.add_other_location(
@@ -1883,7 +1912,7 @@ class Dataset(HDXObject):
1883
1912
  Returns:
1884
1913
  None
1885
1914
  """
1886
- if isinstance(maintainer, user.User) or isinstance(maintainer, dict):
1915
+ if isinstance(maintainer, (user.User, dict)):
1887
1916
  if "id" not in maintainer:
1888
1917
  maintainer = user.User.read_from_hdx(
1889
1918
  maintainer["name"], configuration=self.configuration
@@ -1918,9 +1947,7 @@ class Dataset(HDXObject):
1918
1947
  Returns:
1919
1948
  None
1920
1949
  """
1921
- if isinstance(organization, org_module.Organization) or isinstance(
1922
- organization, dict
1923
- ):
1950
+ if isinstance(organization, (org_module.Organization, dict)):
1924
1951
  if "id" not in organization:
1925
1952
  organization = org_module.Organization.read_from_hdx(
1926
1953
  organization["name"], configuration=self.configuration
@@ -1966,7 +1993,7 @@ class Dataset(HDXObject):
1966
1993
  Returns:
1967
1994
  Dataset showcase dict
1968
1995
  """
1969
- if isinstance(showcase, sc_module.Showcase) or isinstance(showcase, dict):
1996
+ if isinstance(showcase, (sc_module.Showcase, dict)):
1970
1997
  if "id" not in showcase:
1971
1998
  showcase = sc_module.Showcase.read_from_hdx(showcase["name"])
1972
1999
  showcase = showcase["id"]
@@ -1981,7 +2008,7 @@ class Dataset(HDXObject):
1981
2008
  def add_showcase(
1982
2009
  self,
1983
2010
  showcase: Union["Showcase", dict, str],
1984
- showcases_to_check: Sequence["Showcase"] = None,
2011
+ showcases_to_check: Sequence["Showcase"] | None = None,
1985
2012
  ) -> bool:
1986
2013
  """Add dataset to showcase
1987
2014
 
@@ -1995,8 +2022,8 @@ class Dataset(HDXObject):
1995
2022
  dataset_showcase = self._get_dataset_showcase_dict(showcase)
1996
2023
  if showcases_to_check is None:
1997
2024
  showcases_to_check = self.get_showcases()
1998
- for showcase in showcases_to_check:
1999
- if dataset_showcase["showcase_id"] == showcase["id"]:
2025
+ for showcase_to_check in showcases_to_check:
2026
+ if dataset_showcase["showcase_id"] == showcase_to_check["id"]:
2000
2027
  return False
2001
2028
  showcase = sc_module.Showcase(
2002
2029
  {"id": dataset_showcase["showcase_id"]},
@@ -2008,7 +2035,7 @@ class Dataset(HDXObject):
2008
2035
  def add_showcases(
2009
2036
  self,
2010
2037
  showcases: Sequence[Union["Showcase", dict, str]],
2011
- showcases_to_check: Sequence["Showcase"] = None,
2038
+ showcases_to_check: Sequence["Showcase"] | None = None,
2012
2039
  ) -> bool:
2013
2040
  """Add dataset to multiple showcases
2014
2041
 
@@ -2229,7 +2256,7 @@ class Dataset(HDXObject):
2229
2256
  """
2230
2257
  if isinstance(resource, int) and not isinstance(resource, bool):
2231
2258
  resource = self._resources[resource]
2232
- if isinstance(resource, res_module.Resource) or isinstance(resource, dict):
2259
+ if isinstance(resource, (res_module.Resource, dict)):
2233
2260
  res = resource.get("id")
2234
2261
  if res is None:
2235
2262
  resource = resource["name"]
@@ -2576,12 +2603,10 @@ class Dataset(HDXObject):
2576
2603
  return None
2577
2604
  startdate = result.get("startdate")
2578
2605
  if startdate is not None:
2579
- if startdate < dates[0]:
2580
- dates[0] = startdate
2606
+ dates[0] = min(dates[0], startdate)
2581
2607
  enddate = result.get("enddate")
2582
2608
  if enddate is not None:
2583
- if enddate > dates[1]:
2584
- dates[1] = enddate
2609
+ dates[1] = max(dates[1], enddate)
2585
2610
  return row
2586
2611
 
2587
2612
  filepath = Path(folder) / filename
hdx/data/hdxobject.py CHANGED
@@ -425,7 +425,7 @@ class HDXObject(UserDict, ABC):
425
425
  try:
426
426
  if files_to_upload:
427
427
  for key, value in files_to_upload.items():
428
- open_files_to_upload[key] = open(value, "rb")
428
+ open_files_to_upload[key] = open(value, "rb") # noqa: SIM115
429
429
  return self.configuration.call_remoteckan(
430
430
  self.actions()[action], data, files=open_files_to_upload
431
431
  )
@@ -603,7 +603,7 @@ class HDXObject(UserDict, ABC):
603
603
  return False
604
604
  if isinstance(obj, str):
605
605
  obj_id = obj
606
- elif isinstance(obj, dict) or isinstance(obj, HDXObject):
606
+ elif isinstance(obj, (dict, HDXObject)):
607
607
  obj_id = obj.get(matchon)
608
608
  else:
609
609
  raise HDXError("Type of object not a string, dict or T<=HDXObject")
@@ -613,7 +613,7 @@ class HDXObject(UserDict, ABC):
613
613
  objid = objdata.get(matchon)
614
614
  if objid and objid == obj_id:
615
615
  if delete:
616
- objlist[i].delete_from_hdx()
616
+ objdata.delete_from_hdx()
617
617
  del objlist[i]
618
618
  return True
619
619
  return False
hdx/data/location.py CHANGED
@@ -2,11 +2,12 @@
2
2
 
3
3
  import logging
4
4
  from collections.abc import Sequence
5
+ from contextlib import suppress
5
6
  from typing import Any, Optional
6
7
 
7
8
  from hdx.api.configuration import Configuration
8
9
  from hdx.data.activity import Activity
9
- from hdx.data.hdxobject import HDXObject
10
+ from hdx.data.hdxobject import HDXError, HDXObject
10
11
 
11
12
  logger = logging.getLogger(__name__)
12
13
 
@@ -187,12 +188,10 @@ class Location(HDXObject):
187
188
  if name in compiled_locations:
188
189
  final_locations.append(compiled_locations[name])
189
190
  else:
190
- try:
191
+ with suppress(HDXError):
191
192
  missing_location = location._write_to_hdx("show", {"id": name})
192
193
  if missing_location:
193
194
  final_locations.append(missing_location)
194
- except Exception:
195
- pass
196
195
 
197
196
  return final_locations
198
197
 
hdx/data/organization.py CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  import logging
4
4
  from collections.abc import Sequence
5
+ from contextlib import suppress
5
6
  from pathlib import Path
6
7
  from typing import TYPE_CHECKING, Any, Optional, Union
7
8
 
@@ -303,12 +304,10 @@ class Organization(HDXObject):
303
304
  if name in compiled_orgs:
304
305
  final_orgs.append(compiled_orgs[name])
305
306
  else:
306
- try:
307
+ with suppress(HDXError):
307
308
  missing_org = organization._write_to_hdx("show", {"id": name})
308
309
  if missing_org:
309
310
  final_orgs.append(missing_org)
310
- except Exception:
311
- pass
312
311
 
313
312
  return final_orgs
314
313
 
hdx/data/resource.py CHANGED
@@ -8,7 +8,7 @@ from pathlib import Path, PureWindowsPath
8
8
  from typing import Any, Optional
9
9
  from urllib.parse import urlsplit
10
10
 
11
- from hdx.utilities.dateparse import now_utc, now_utc_notz, parse_date
11
+ from hdx.utilities.dateparse import now_utc_notz, parse_date
12
12
  from hdx.utilities.downloader import Download
13
13
  from hdx.utilities.file_hashing import get_size_and_hash
14
14
  from hdx.utilities.retriever import Retrieve
@@ -132,7 +132,7 @@ class Resource(HDXObject):
132
132
  def get_date_of_resource(
133
133
  self,
134
134
  date_format: str | None = None,
135
- today: datetime = now_utc(),
135
+ today: datetime | None = None,
136
136
  ) -> dict:
137
137
  """Get resource date as datetimes and strings in specified format. If no format
138
138
  is supplied, the ISO 8601 format is used. Returns a dictionary containing keys
@@ -446,7 +446,7 @@ class Resource(HDXObject):
446
446
  if self._file_to_upload is None and "url" not in self.data:
447
447
  raise HDXError("Either a url or a file to upload must be supplied!")
448
448
 
449
- def correct_format(self, data: dict = None) -> None:
449
+ def correct_format(self, data: dict | None = None) -> None:
450
450
  """Correct the format of the file
451
451
 
452
452
  Args:
@@ -744,7 +744,7 @@ class Resource(HDXObject):
744
744
 
745
745
  resources = []
746
746
  resource = Resource(configuration=configuration)
747
- success, result = resource._read_from_hdx(
747
+ _success, result = resource._read_from_hdx(
748
748
  "resource", query, "query", Resource.actions()["search"]
749
749
  )
750
750
  if result:
@@ -1257,7 +1257,7 @@ class Resource(HDXObject):
1257
1257
  if is_valid_uuid(resource_view_id) is False:
1258
1258
  raise HDXError(f"{resource_view} is not a valid resource view id!")
1259
1259
  ids.append(resource_view_id)
1260
- _, result = self._read_from_hdx(
1260
+ self._read_from_hdx(
1261
1261
  "resource view",
1262
1262
  self.data["id"],
1263
1263
  "id",
@@ -46,9 +46,8 @@ class ResourceMatcher:
46
46
  for i, name1 in enumerate(names1):
47
47
  if name1 != name2:
48
48
  continue
49
- if name1 in dupnames:
50
- if formats1[i] != format2:
51
- continue
49
+ if name1 in dupnames and formats1[i] != format2:
50
+ continue
52
51
  index1_match = i
53
52
  return index1_match
54
53
 
@@ -83,10 +82,9 @@ class ResourceMatcher:
83
82
  for j, id2 in enumerate(ids2):
84
83
  if id2 is None:
85
84
  continue
86
- if id1 == id2:
87
- if groups1[i] == groups2[j]:
88
- index1_matches.append(i)
89
- index2_matches.append(j)
85
+ if id1 == id2 and groups1[i] == groups2[j]:
86
+ index1_matches.append(i)
87
+ index2_matches.append(j)
90
88
  dupnames1 = {
91
89
  item for item, count in collections.Counter(names1).items() if count > 1
92
90
  }
@@ -102,9 +100,8 @@ class ResourceMatcher:
102
100
  continue
103
101
  if name1 != name2:
104
102
  continue
105
- if name1 in dupnames:
106
- if formats1[i] != formats2[j]:
107
- continue
103
+ if name1 in dupnames and formats1[i] != formats2[j]:
104
+ continue
108
105
  if groups1[i] == groups2[j]:
109
106
  index1_matches.append(i)
110
107
  index2_matches.append(j)
hdx/data/resource_view.py CHANGED
File without changes
hdx/data/showcase.py CHANGED
@@ -246,7 +246,7 @@ class Showcase(HDXObject):
246
246
  Returns:
247
247
  showcase dataset dict
248
248
  """
249
- if isinstance(dataset, hdx.data.dataset.Dataset) or isinstance(dataset, dict):
249
+ if isinstance(dataset, (hdx.data.dataset.Dataset, dict)):
250
250
  if "id" not in dataset:
251
251
  dataset = hdx.data.dataset.Dataset.read_from_hdx(dataset["name"])
252
252
  dataset = dataset["id"]
@@ -261,7 +261,7 @@ class Showcase(HDXObject):
261
261
  def add_dataset(
262
262
  self,
263
263
  dataset: Union["Dataset", dict, str], # noqa: F821
264
- datasets_to_check: Sequence["Dataset"] = None, # noqa: F821
264
+ datasets_to_check: Sequence["Dataset"] | None = None, # noqa: F821
265
265
  ) -> bool:
266
266
  """Add a dataset
267
267
 
@@ -275,8 +275,8 @@ class Showcase(HDXObject):
275
275
  showcase_dataset = self._get_showcase_dataset_dict(dataset)
276
276
  if datasets_to_check is None:
277
277
  datasets_to_check = self.get_datasets()
278
- for dataset in datasets_to_check:
279
- if showcase_dataset["package_id"] == dataset["id"]:
278
+ for dataset_to_check in datasets_to_check:
279
+ if showcase_dataset["package_id"] == dataset_to_check["id"]:
280
280
  return False
281
281
  self._write_to_hdx("associate", showcase_dataset, "package_id")
282
282
  return True
@@ -284,7 +284,7 @@ class Showcase(HDXObject):
284
284
  def add_datasets(
285
285
  self,
286
286
  datasets: Sequence[Union["Dataset", dict, str]], # noqa: F821
287
- datasets_to_check: Sequence["Dataset"] = None, # noqa: F821
287
+ datasets_to_check: Sequence["Dataset"] | None = None, # noqa: F821
288
288
  ) -> bool:
289
289
  """Add multiple datasets
290
290
 
hdx/data/user.py CHANGED
@@ -263,7 +263,7 @@ class User(HDXObject):
263
263
  **kwargs,
264
264
  )
265
265
 
266
- def get_organization_dicts(self, permission: str = "read") -> list[dict]: # noqa: F821
266
+ def get_organization_dicts(self, permission: str = "read") -> list[dict]:
267
267
  """Get organization dictionaries (not organization objects) in HDX that this user is a member of.
268
268
 
269
269
  Args:
@@ -340,7 +340,7 @@ class User(HDXObject):
340
340
  return user.configuration.call_remoteckan(
341
341
  cls.actions()["listorgs"], {"permission": permission}
342
342
  )
343
- except Exception:
343
+ except Exception: # noqa: BLE001
344
344
  return []
345
345
 
346
346
  @classmethod
hdx/data/vocabulary.py CHANGED
@@ -34,7 +34,7 @@ class Vocabulary(HDXObject):
34
34
  def __init__(
35
35
  self,
36
36
  initial_data: dict | None = None,
37
- name: str = None,
37
+ name: str | None = None,
38
38
  tags: list | None = None,
39
39
  configuration: Configuration | None = None,
40
40
  ) -> None:
@@ -361,9 +361,7 @@ class Vocabulary(HDXObject):
361
361
  Returns:
362
362
  True if tag is approved, False if not
363
363
  """
364
- if tag.lower() in cls.approved_tags(configuration):
365
- return True
366
- return False
364
+ return tag.lower() in cls.approved_tags(configuration)
367
365
 
368
366
  @classmethod
369
367
  def read_tags_mappings(
hdx/facades/__init__.py CHANGED
File without changes
@@ -85,11 +85,10 @@ def facade(projectmainfn: Callable[[Any], None], **kwargs: Any):
85
85
  main_sig = f"{projectmainname}({','.join(param_names)})"
86
86
 
87
87
  argv = sys.argv[1:]
88
- for key in kwargs:
88
+ for key, value in kwargs.items():
89
89
  name = f"--{key.replace('_', '-')}"
90
90
  if name not in argv:
91
91
  argv.append(name)
92
- value = kwargs[key]
93
92
  if isinstance(value, Path):
94
93
  value = str(value)
95
94
  argv.append(value)
File without changes
hdx/facades/simple.py CHANGED
File without changes
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: hdx-python-api
3
- Version: 6.7.7
3
+ Version: 6.7.9
4
4
  Summary: HDX Python API for interacting with the Humanitarian Data Exchange
5
5
  Project-URL: Homepage, https://github.com/OCHA-DAP/hdx-python-api
6
6
  Author: Michael Rans
@@ -27,8 +27,8 @@ Requires-Python: >=3.11
27
27
  Requires-Dist: ckanapi>=4.11
28
28
  Requires-Dist: defopt>=7.0.0
29
29
  Requires-Dist: email-validator
30
- Requires-Dist: hdx-python-country>=4.2.6
31
- Requires-Dist: hdx-python-utilities>=4.2.5
30
+ Requires-Dist: hdx-python-country>=4.3.1
31
+ Requires-Dist: hdx-python-utilities>=4.2.7
32
32
  Requires-Dist: makefun
33
33
  Requires-Dist: requests
34
34
  Provides-Extra: docs
@@ -0,0 +1,33 @@
1
+ hdx/api/__init__.py,sha256=11ozJKiUsqDCZ3_mcAHhGYUyGK_Unl54djVSBBExFB4,59
2
+ hdx/api/_version.py,sha256=mqZBEZ3sW4hFzYhXwQAxPeU7oI9pRVlb2fo16Eapuxc,520
3
+ hdx/api/configuration.py,sha256=40DTsYVCe1tQ5IVQPFdhW83CemzkEXMjNBk6WVeUkj8,23802
4
+ hdx/api/hdx_base_configuration.yaml,sha256=jj2t5b7NnI499rHVwOjj3Q5BAjE8i7NDGVKnWZ5P5-4,2222
5
+ hdx/api/locations.py,sha256=bFl_cKz_AEQzkE_xWOkrRlUQ0GT2LMPSk-G_LsbV-Ns,4099
6
+ hdx/api/remotehdx.py,sha256=IjKwP3jutlkrjvWCJPP7YM-xzg3pP_QVmiJfblllBY0,2079
7
+ hdx/api/utilities/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ hdx/api/utilities/date_helper.py,sha256=MIUh-QRGXTqjmbhCx0YDrpbfS4hcYN83cq-KYtW16oo,6413
9
+ hdx/api/utilities/filestore_helper.py,sha256=0FcUpGHpYlAzlNDpDxdXbSqV6VHFfGCLakCmK37hieU,6917
10
+ hdx/api/utilities/hdx_error_handler.py,sha256=jmgp6dtflhYDlZ1y8pMBDZF9eJhoIxS-ZccIBculVeg,8841
11
+ hdx/api/utilities/hdx_state.py,sha256=KzrK0A-H5R6cRPqwF4d23_S_zfIa1ow4K5u46FesGmY,2442
12
+ hdx/api/utilities/hdx_stats.py,sha256=JlEcF9LN-OjcVeh6C0te-nAlcO7W-JIpD5JJWTiWxs0,2847
13
+ hdx/api/utilities/url_utils.py,sha256=Pb4r-BAqIHYmeoB_i7QjutDp6nOAUh_OHvCtiNLda3Y,4534
14
+ hdx/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
+ hdx/data/activity.py,sha256=YNa7hAgsMP96EIUX7UMInxAXnJ8TynE1KpecRrv8Vso,9200
16
+ hdx/data/dataset.py,sha256=wbo2ShjXjelZcLm4I8V9wx-RDf_lXf2FsUjH-74VvWU,106379
17
+ hdx/data/hdxobject.py,sha256=SCrnmOhBtP-6-1EdKzjgV4u0aclTzDhA4QghsaQ0qN4,28379
18
+ hdx/data/location.py,sha256=eEdHZGEYKa9qRDyYqGTwAh22TB4XBkcTu47Mz39fmEs,11171
19
+ hdx/data/organization.py,sha256=T2lITJXEYDN5t8dYkfcQTe-x0joULTtgp3Vn9JeVh-k,13133
20
+ hdx/data/resource.py,sha256=3U91qdeDBUPPfB1eVLk42QOGc_tNooN8KCSWx0zhgWM,57590
21
+ hdx/data/resource_matcher.py,sha256=JM4Lg1ONAediSDIwAPEFeE6QNneeRM_4F2IdFBgNMbU,4175
22
+ hdx/data/resource_view.py,sha256=GcYkh0iDAe6_m2ErY_A6i3Z7ZFX949eGt1TLnLZv_8s,7346
23
+ hdx/data/showcase.py,sha256=tXtE29JR_kTvXm5n9Rsd2D5KTAMfSBBPTgIQrzjabXo,14073
24
+ hdx/data/user.py,sha256=3qwX945-Jj-F1tMRltB-3CDj5bKN67nTw3XkbYRfrXE,17322
25
+ hdx/data/vocabulary.py,sha256=1gAfg_TEBKvvkhTDDJxr3IkL40OWaT5wA_xHCsTY8qM,20741
26
+ hdx/facades/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
+ hdx/facades/infer_arguments.py,sha256=3Z5vPPkni0Cgg9cUb7wDF_8TxeX1TiiffcnGqyahtiY,4015
28
+ hdx/facades/keyword_arguments.py,sha256=aVapHCfqBO6H7xxBgTdK9ISdgrBFsNypPDWihfQ3edU,1125
29
+ hdx/facades/simple.py,sha256=QWsBkaHG_UM6X3Zu2u3LWVOQzeR24q-EUClrfsL_mkM,1064
30
+ hdx_python_api-6.7.9.dist-info/METADATA,sha256=640fkpkJHrkSRiYLy1UUP9hJ-jxQgEWMz-GIB8U5Dr0,4895
31
+ hdx_python_api-6.7.9.dist-info/WHEEL,sha256=2iZrJkDIkeDh0k9SikKMqFuRP-ua6mb4Ir1AsER4BEw,87
32
+ hdx_python_api-6.7.9.dist-info/licenses/LICENSE,sha256=wc-4GpMn-ODs-U_bTe1YCiPVgvcjzrpYOx2wPuyAeII,1079
33
+ hdx_python_api-6.7.9.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.32.4
2
+ Generator: hatchling 1.33.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,33 +0,0 @@
1
- hdx/api/__init__.py,sha256=11ozJKiUsqDCZ3_mcAHhGYUyGK_Unl54djVSBBExFB4,59
2
- hdx/api/_version.py,sha256=vmqSkLqNCymV_Igs64SsTf8xbvuIFzv8XLWjCoHHoKw,520
3
- hdx/api/configuration.py,sha256=9WvuVI-3th2Dv70_t_4VoyrlJwB_9qUSN5_zUKbp4sQ,23805
4
- hdx/api/hdx_base_configuration.yaml,sha256=jj2t5b7NnI499rHVwOjj3Q5BAjE8i7NDGVKnWZ5P5-4,2222
5
- hdx/api/locations.py,sha256=bFl_cKz_AEQzkE_xWOkrRlUQ0GT2LMPSk-G_LsbV-Ns,4099
6
- hdx/api/remotehdx.py,sha256=IjKwP3jutlkrjvWCJPP7YM-xzg3pP_QVmiJfblllBY0,2079
7
- hdx/api/utilities/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
- hdx/api/utilities/date_helper.py,sha256=KZE2sG0LM4gRa8ubNMaPFOoQl6giYoJUd7QNWQQf798,6355
9
- hdx/api/utilities/filestore_helper.py,sha256=0FcUpGHpYlAzlNDpDxdXbSqV6VHFfGCLakCmK37hieU,6917
10
- hdx/api/utilities/hdx_error_handler.py,sha256=x1rb2qBO0C6CJjqToSFj_XB1F3pf3nHpA8otxXfTFzA,8711
11
- hdx/api/utilities/hdx_state.py,sha256=KzrK0A-H5R6cRPqwF4d23_S_zfIa1ow4K5u46FesGmY,2442
12
- hdx/api/utilities/hdx_stats.py,sha256=JlEcF9LN-OjcVeh6C0te-nAlcO7W-JIpD5JJWTiWxs0,2847
13
- hdx/api/utilities/url_utils.py,sha256=Pb4r-BAqIHYmeoB_i7QjutDp6nOAUh_OHvCtiNLda3Y,4534
14
- hdx/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
- hdx/data/activity.py,sha256=YNa7hAgsMP96EIUX7UMInxAXnJ8TynE1KpecRrv8Vso,9200
16
- hdx/data/dataset.py,sha256=-GQO08PK8u19O0qRWttg3AuPskPCwjffcE2mPq-7dQE,105903
17
- hdx/data/hdxobject.py,sha256=EG5KkVpi-yF6m6HVF79EqDneq1W7mo5M-bPJHG79T0I,28383
18
- hdx/data/location.py,sha256=UJPGKc8euAYFJsUFkdQtViLUwqNWYOWwaLELApAMHk4,11168
19
- hdx/data/organization.py,sha256=IRen2F2NsXLC8r-PVTS9eQp7LTn_44OcDUa1S7SCKiQ,13140
20
- hdx/data/resource.py,sha256=XgYDGD5mYc89uaiRi0oamVJ5FTFSOV6QO_Nx-9_rjpo,57601
21
- hdx/data/resource_matcher.py,sha256=Yzk9pWa4zk1p09m6zcZMj0XZf5Y16Pa3KToOdUt7rP8,4247
22
- hdx/data/resource_view.py,sha256=GcYkh0iDAe6_m2ErY_A6i3Z7ZFX949eGt1TLnLZv_8s,7346
23
- hdx/data/showcase.py,sha256=vnRZ45xd9Ct65eFQkWZtMIJPFifZfKOrH4obO5D5Pvc,14062
24
- hdx/data/user.py,sha256=NXBuvUu-pNVSEelL59wdNQgeWmDgeWke_6JxViww3Cc,17320
25
- hdx/data/vocabulary.py,sha256=sDDVh9ivCbZlPKXIdOoj0ltTdRufL0ypfGZUirIb2IA,20776
26
- hdx/facades/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
- hdx/facades/infer_arguments.py,sha256=DvyDuozfOPmoaV7HjhQySojGIrMWW9nos31auQBVVl8,4032
28
- hdx/facades/keyword_arguments.py,sha256=aVapHCfqBO6H7xxBgTdK9ISdgrBFsNypPDWihfQ3edU,1125
29
- hdx/facades/simple.py,sha256=QWsBkaHG_UM6X3Zu2u3LWVOQzeR24q-EUClrfsL_mkM,1064
30
- hdx_python_api-6.7.7.dist-info/METADATA,sha256=aCpCaXGb8JL15Aw2wnOZkEMEflXwdQGXe7IY7RzL0y4,4895
31
- hdx_python_api-6.7.7.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
32
- hdx_python_api-6.7.7.dist-info/licenses/LICENSE,sha256=wc-4GpMn-ODs-U_bTe1YCiPVgvcjzrpYOx2wPuyAeII,1079
33
- hdx_python_api-6.7.7.dist-info/RECORD,,