How to get the Region Name for AWS Price List API using Python and Boto3

Last Updated on May 2, 2021

When using the AWS Price List API, one of the most used attribute is the location attribute. This attribute is used to filter the region of your target resource.

Unfortunately, the location attribute is not in the region code that we use when programming in Python and Boto3, like us-east-1. Instead, it is descriptive like US East (N. Virginia). This is not readily available in Boto3 client or resource.

Below is the python function get_region_name, this converts the region code, eu-west-2, to the region name that AWS Price List API attribute location will accept, EU (London).

import json
from pkg_resources import resource_filename

def get_region_name(region_code):

    endpoint_file = resource_filename('botocore', 'data/endpoints.json')

    with open(endpoint_file, 'r') as f:
        endpoint_data = json.load(f)

    region_name = endpoint_data['partitions'][0]['regions'][region_code]['description']

    region_name = region_name.replace('Europe', 'EU')

    return region_name


if __name__ == "__main__":
    region_code = 'ap-south-1'
    region_name = get_region_name(region_code)
    print(region_name)

    region_code = 'eu-west-2'
    region_name = get_region_name(region_code)
    print(region_name)

    region_code = 'us-east-2'
    region_name = get_region_name(region_code)
    print(region_name)

Output

Asia Pacific (Mumbai)
EU (London)
US East (Ohio)

Code Explained

We first take the filepath of the endpoints.json inside the botocore library.

endpoint_file = resource_filename('botocore', 'data/endpoints.json')

Since boto3 is built atop of the botocore library, when we install boto3 it will automatically install botocore.

Then we access the contents of the endpoints.json file, convert it to dictionary using json.load and store to the endpoint_data variable.

with open(endpoint_file, 'r') as f:
    endpoint_data = json.load(f)

Then get the region name from the dictionary and return it.

region_name = endpoint_data['partitions'][0]['regions'][region_code]['description']

We need to modify all Europe Regions since the location attribute does not support values with Europe, it support EU instead.

region_name = region_name.replace('Europe', 'EU')

Then return the region_name.

return region_name

Getting the Region Names of All Regions

If you want to list all the active region codes and region names in the AWS Account, then change the main part of the code to this.

if __name__ == "__main__":

    import boto3

    ec2_client = boto3.client('ec2')

    response = ec2_client.describe_regions(AllRegions=True)

    regions = response['Regions']

    for region in regions:
        region_code = region['RegionName']

        region_name = get_region_name(region_code)

        print(region_code, '\t', region_name)

Output

af-south-1       Africa (Cape Town)
eu-north-1       EU (Stockholm)
ap-south-1       Asia Pacific (Mumbai)
eu-west-3        EU (Paris)
eu-west-2        EU (London)
eu-south-1       EU (Milan)
eu-west-1        EU (Ireland)
ap-northeast-3   Asia Pacific (Osaka)
ap-northeast-2   Asia Pacific (Seoul)
me-south-1       Middle East (Bahrain)
ap-northeast-1   Asia Pacific (Tokyo)
sa-east-1        South America (Sao Paulo)
ca-central-1     Canada (Central)
ap-east-1        Asia Pacific (Hong Kong)
ap-southeast-1   Asia Pacific (Singapore)
ap-southeast-2   Asia Pacific (Sydney)
eu-central-1     EU (Frankfurt)
us-east-1        US East (N. Virginia)
us-east-2        US East (Ohio)
us-west-1        US West (N. California)
us-west-2        US West (Oregon)

Efficient access to Region Names multiple times

If your program will be accessing the different region names multiple times then I suggest creating a dictionary where the key is the region code and the values is the region name. This implementation will be faster.

See get_region_code_name_dict function below for this implementation.

import json
from pkg_resources import resource_filename

def get_region_code_name_dict():

    endpoint_file = resource_filename('botocore', 'data/endpoints.json')

    with open(endpoint_file, 'r') as f:
        endpoint_data = json.load(f)

    regions = endpoint_data['partitions'][0]['regions']

    region_code_name_dict = {}

    for region_code in regions.keys():
        region_name = regions[region_code]['description']
        region_code_name_dict[region_code] = region_name.replace('Europe', 'EU')

    return region_code_name_dict


if __name__ == "__main__":
    
    # regions_code_name_dict is a dictionary that has the region_code as the key and the region_name as the value
    regions_code_name_dict = get_region_code_name_dict()

    region_code = 'us-east-1'
    region_name = regions_code_name_dict[region_code]
    print(region_name)

    region_code = 'ap-southeast-2'
    region_name = regions_code_name_dict[region_code]
    print(region_name)

    region_code = 'eu-central-1'
    region_name = regions_code_name_dict[region_code]
    print(region_name)

Output

US East (N. Virginia)
Asia Pacific (Sydney)
EU (Frankfurt)

If we do print(region_code_name_dict) it will look like this. (Manually formatted for easier reading)

{
    'af-south-1': 'Africa (Cape Town)',
    'ap-east-1': 'Asia Pacific (Hong Kong)',
    'ap-northeast-1': 'Asia Pacific (Tokyo)',
    'ap-northeast-2': 'Asia Pacific (Seoul)',
    'ap-northeast-3': 'Asia Pacific (Osaka)',
    'ap-south-1': 'Asia Pacific (Mumbai)',
    'ap-southeast-1': 'Asia Pacific (Singapore)',
    'ap-southeast-2': 'Asia Pacific (Sydney)',
    'ca-central-1': 'Canada (Central)',
    'eu-central-1': 'EU (Frankfurt)',
    'eu-north-1': 'EU (Stockholm)',
    'eu-south-1': 'EU (Milan)',
    'eu-west-1': 'EU (Ireland)',
    'eu-west-2': 'EU (London)',
    'eu-west-3': 'EU (Paris)',
    'me-south-1': 'Middle East (Bahrain)',
    'sa-east-1': 'South America (Sao Paulo)',
    'us-east-1': 'US East (N. Virginia)',
    'us-east-2': 'US East (Ohio)',
    'us-west-1': 'US West (N. California)',
    'us-west-2': 'US West (Oregon)'
}

Lambda Functions delay in boto3 updates

When Asia Pacific (Osaka) or ap-northeast-3 was recently launched, the get_region_name was throwing a KeyError: ap-northeast-3. When we investigated, it turns out that the boto3 and botocore was not yet updated during development.

To solve this, either upload the updated package of boto3 and botocore to the Lambda Function or use a try/except block that would handle the new region_code just like the code below.

import json
from pkg_resources import resource_filename

def get_region_name(region_code):

    endpoint_file = resource_filename('botocore', 'data/endpoints.json')

    with open(endpoint_file, 'r') as f:
        endpoint_data = json.load(f)

    try:
        region_name = endpoint_data['partitions'][0]['regions'][region_code]['description']

        region_name = region_name.replace('Europe', 'EU')

    except Exception as e:
        if region_code == 'ap-northeast-3':
            return 'Asia Pacific (Osaka)'
        
        raise e         # Raise an exception when the region_code cannot be found

    return region_name


if __name__ == "__main__":

    region_name = get_region_name('ap-northeast-3')

    print(region_name)

The best method is to actually use an updated local boto3 package in Lambda, but if you are the type that tries to avoid uploading a python package then the code above would help.


KeyError on non-Lambda Python Environment

If you are developing not for Lambda Functions, like a development, staging or production environment running locally or on services, check the latest endpoints.json of botocore in the master branch of their github repository.

If there is an entry of the region code that raises an exception, then an update to your boto3 package will do the trick.

To update boto3, just run the command below.

pip3 install boto3 --upgrade

I hope the above helps in getting the Region Name that you need for the Boto3 AWS Price List API.

Leave a Reply

Your email address will not be published. Required fields are marked *