Skip to content

Commit

Permalink
Refactor and add SIDS, LDC and LLDC
Browse files Browse the repository at this point in the history
  • Loading branch information
andy-isoc committed Nov 15, 2024
1 parent cba9019 commit 8561c44
Show file tree
Hide file tree
Showing 2 changed files with 175 additions and 71 deletions.
246 changes: 175 additions & 71 deletions django_countries_hdx/__init__.py
Original file line number Diff line number Diff line change
@@ -1,125 +1,229 @@
from pathlib import Path

from hdx.location.country import Country

from django_countries_hdx.country_regions import COUNTRY_REGIONS
from django_countries_hdx.regions import REGIONS, SUBREGIONS

# custom_file_url = Path(__file__).parent.resolve() / "hdx_plus_m49.csv"
# This next will need to change once our PR in the hdx lib has been merged
# Country.set_ocha_url(str(custom_file_url))
Country.set_use_live_default(False)


def get_country_data(country_code: str) -> dict[str, str] | None:
"""Retrieves annotated country information. Will accept either ISO2 or ISO3 country code.
:param country_code: ISO2 or ISO3 country code.
:return: Dictionary of country information with HXL hashtags as keys.
"""
if country_code is None:
return None

if len(country_code) == 2:
return Country.get_country_info_from_iso2(country_code)

return Country.get_country_info_from_iso3(country_code)


def get_region_name(region_code: int) -> str | None:
"""Retrieves region or sub-region name for a region code.
:param region_code: UN M49 region code.
:return: String. Region name
"""
if not region_code:
return None

try:
countriesdata = Country.countriesdata()
return countriesdata["regioncodes2names"].get(region_code) # noqa
except KeyError:
return None

def get_countries_by_region() -> dict[int, dict[str, list[tuple[str, str]]]]:
"""Retrieves lists of countries keyed by region, with region name and country tuples.
:param regions: Boolean to determine whether to use regions or subregions.
:return: Dict. Keyed by region code, the value is a dictionary containing the
region name and a list of country_code, country_name tuples.
"""
region_codes = (2, 9, 19, 142, 150,)

return {
region_code: {
"name": get_region_name(region_code),
"countries": sorted(
[
(
Country.get_iso2_from_iso3(code),
Country.get_country_name_from_iso3(code)
)
for code in Country.get_countries_in_region(region_code)
],
key=lambda x: x[1] # Sort by country name
)
}
for region_code in sorted(region_codes, key=lambda x: get_region_name(x))
}


def get_countries_by_subregion() -> dict[int, dict[str, list[tuple[str, str]]]]:
"""Retrieves lists of countries keyed by region, with region name and country tuples.
:param regions: Boolean to determine whether to use regions or subregions.
:return: Dict. Keyed by region code, the value is a dictionary containing the
region name and a list of country_code, country_name tuples.
"""
subregion_codes = (
5, 11, 13, 14, 15, 17, 18, 21, 29, 30, 34, 35, 39, 53, 54, 57, 61, 143, 145, 151, 154, 155,
)

return {
region_code: {
"name": get_region_name(region_code),
"countries": sorted(
[
(
Country.get_iso2_from_iso3(code),
Country.get_country_name_from_iso3(code)
)
for code in Country.get_countries_in_region(region_code)
],
key=lambda x: x[1] # Sort by country name
)
}
for region_code in sorted(subregion_codes, key=lambda x: get_region_name(x))
}


def get_countries_in_region(region_code: int) -> list[tuple[str, str]] | None:
"""Retrieves lists of countries in a region/sub-region.
:return: List. ISO2 country_code, country_name tuples.
"""
if not region_code:
return None

countries_iso3 = Country.get_countries_in_region(region_code)

countries_list = [(
Country.get_iso2_from_iso3(code),
Country.get_country_name_from_iso3(code)
) for code in countries_iso3
]

return countries_list


class Regions:
"""
An object that can query a UN M49 list of geographical regions and subregions and return a list of countries in
that region.
"""

def country_region(self, country_code: str, region: bool = True) -> str | None:
def country_region(self, country_code: str) -> int | None:
"""Return a UN M49 region code for a country.
Extends django-countries by adding a .region method to the Country field.
Extends django-countries by adding a .region() method to the Country field.
:param country_code: Two-letter ISO country code.
:param region: Boolean. Region lookup if True, Sub-region if False.
:return: String. UN M49 region code.
:return: Integer. UN M49 region code.
"""
code_to_use = "un_region_code" if region else "un_subregion_code"
try:
return COUNTRY_REGIONS[country_code][code_to_use]
except KeyError:
country_data = get_country_data(country_code)
if country_data:
return int(country_data["#region+code+main"])
else:
return None

def country_region_name(self, country_code: str) -> str | None:
"""Return the region name for a country
"""Retrieves region name for a country.
Extends django-countries by adding a .region_name() method to the Country field.
:param country_code: Two-letter ISO country code.
:return: String
:return: String. Region name
"""
region_code = self.country_region(country_code)
country_data = get_country_data(country_code)

if country_data:
return country_data["#region+main+name+preferred"]

if region_code:
try:
return self.region_name(region_code)
except KeyError:
return None
return None

def country_subregion(self, country_code: str) -> str | None:
def country_subregion(self, country_code: str) -> int | None:
"""Return a UN M49 sub-region code for a country.
Extends django-countries by adding a .subregion method to the Country field.
Extends django-countries by adding a .subregion() method to the Country field.
:param country_code: Two-letter ISO country code.
:return: String. UN M49 sub-region code.
:return: Integer. UN M49 sub-region code.
"""
try:
return self.country_region(country_code, region=False)
except KeyError:
return None
country_data = get_country_data(country_code)

if country_data:
# Return the intermediate region if populated.
intermediate_region = country_data.get("#region+code+intermediate", None)

if intermediate_region:
return int(intermediate_region)
else:
return int(country_data["#region+code+sub"])

return None

def country_subregion_name(self, country_code: str) -> str | None:
"""Return the sub-region name for a country
:param country_code: Two-letter ISO country code.
:return: String
"""
region_code = self.country_subregion(country_code)
country_data = get_country_data(country_code)

if country_data:
# Return the intermediate region if populated.
intermediate_region = country_data.get("#region+intermediate+name+preferred", None)
return intermediate_region or country_data["#region+name+preferred+sub"]

if region_code:
try:
return self.subregion_name(region_code)
except KeyError:
return None
return None

def countries_by_region(self, region_code: str, region: bool = True) -> str | None:
"""Return a list of country codes found within a region.
def is_sids(self, country_code: str) -> bool | None:
"""Returns whether a country is classed as a SIDS
:param region_code: UN M49 region code.
:param region: Boolean. Region lookup if True, Sub-region if False.
:return: List of two-letter ISO country codes.
:param country_code: Two-letter ISO country code.
:return: Boolean
"""
if region_code:
if region:
try:
return REGIONS[region_code]["countries"]
except KeyError:
return None
else:
return SUBREGIONS[region_code]["countries"]
return None
country_data = get_country_data(country_code)

def countries_by_subregion(self, region_code: str) -> str | None:
"""Return a list of country codes found within a sub-region
if country_data:
return bool(country_data["#meta+bool+sids"])

:param region_code: UN M49 sub-region code.
:return: List of two-letter ISO country codes.
"""
if region_code:
try:
return self.countries_by_region(region_code, region=False)
except KeyError:
return None
return None

def region_name(self, region_code: str) -> str | None:
"""Return the region name
def is_ldc(self, country_code: str) -> bool | None:
"""Returns whether a country is classed as a LDC
:param region_code: UN M49 region code.
:return: String
:param country_code: Two-letter ISO country code.
:return: Boolean
"""
if region_code:
try:
return REGIONS[region_code]["name"]
except KeyError:
return None
country_data = get_country_data(country_code)

if country_data:
return bool(country_data["#meta+bool+ldc"])

return None

def subregion_name(self, region_code: str) -> str | None:
"""Return the region name
def is_lldc(self, country_code: str) -> bool | None:
"""Returns whether a country is classed as a LLDC
:param region_code: UN M49 sub-region code.
:return: String
:param country_code: Two-letter ISO country code.
:return: Boolean
"""
if region_code:
try:
return SUBREGIONS[region_code]["name"]
except KeyError:
return None
country_data = get_country_data(country_code)

if country_data:
return bool(country_data["#meta+bool+lldc"])

return None


Expand Down
File renamed without changes.

0 comments on commit 8561c44

Please sign in to comment.