From ac72b2076cc9ad8f10634dc4fb972aa75dd17591 Mon Sep 17 00:00:00 2001 From: AJ <46843456+amckenna41@users.noreply.github.com> Date: Mon, 23 Oct 2023 15:03:55 +0100 Subject: [PATCH] updating api, unit tests --- .github/workflows/build_test.yml | 10 +- API.md | 111 +----- ATTRIBUTES.md | 58 +-- README.md | 24 +- ToDo.md | 11 +- index.py | 105 ++---- static/README.md | 10 +- static/js/script.js | 16 +- templates/index.html | 62 ++-- tests/test_iso3166_2_api.py | 583 ++++++++++++------------------- 10 files changed, 329 insertions(+), 661 deletions(-) diff --git a/.github/workflows/build_test.yml b/.github/workflows/build_test.yml index 5836109..b5765c2 100644 --- a/.github/workflows/build_test.yml +++ b/.github/workflows/build_test.yml @@ -41,11 +41,13 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip3 install pytest - pip3 install pytest-cov - pip3 install bandit - pip3 install safety + pip install pytest + pip install pytest-cov + pip install bandit + pip install safety pip install codecov + pip install iso3166-2 + pip install importlib-metadata pip install beautifulsoup4 if [ -f requirements.txt ]; then pip install -r requirements.txt; fi diff --git a/API.md b/API.md index c9cbf07..bef606e 100644 --- a/API.md +++ b/API.md @@ -13,7 +13,7 @@ The other endpoints available in the API are: Three paths/endpoints are available in the API - `/api/all`, `/api/alpha2` and `/api/name`. -* The `/api/all` path/endpoint returns all of the ISO 3166 country data for all countries (due to the size of the object this can take some time to load). +* The `/api/all` path/endpoint returns all of the ISO 3166 subdivision data for all countries. * The 2 letter alpha-2 country code can be appended to the **alpha2** path/endpoint e.g /api/alpha2/JP. A single alpha-2 or list of them can be passed to the API e.g /api/alpha2/FR,DE,HU,ID,MA. For redudancy, the 3 letter alpha-3 counterpart for each country's alpha-2 code can also be appened to the path e.g /api/alpha2/FRA,DEU,HUN,IDN,MAR. If an invalid alpha-2 code is input then an error will be returned. @@ -21,11 +21,9 @@ Three paths/endpoints are available in the API - `/api/all`, `/api/alpha2` and ` * The main API endpoint (`/` or `/api`) will return the homepage and API documentation. -The `filter` query string parameter can be appended to any of the endpoints. It accepts a string of one or more attributes that the user wants to only be returned from their request e.g /api/alpha2/IE?filter=capital,currencies,languages,region. This example means that only the capital city, currencies, languages and region data for Ireland will be returned. If an invalid attribute name is input then it will be removed from the request. - The full list of attributes available for each country are available in the [ATTRIBUTES.md][attributes] file. -The API documentation and usage with all useful commands and examples to the API is available below. A demo of the software and API are available [here][demo]. +The API documentation and usage with all useful commands and examples to the API is available on the [API.md][api_md] file. A demo of the software and API are available [here][demo]. Get All ISO 3166-2 updates for all countries ------------------------------------------- @@ -39,7 +37,7 @@ Get All ISO 3166-2 updates for all countries content-type: application/json date: Tue, 20 Dec 2022 17:29:39 GMT server: Vercel - content-length: 202273 + content-length: 837958 {"AD":..., "AE":...} @@ -66,7 +64,7 @@ function getData() { var data = JSON.parse(this.response) ``` -Get all country and ISO 3166-2 data for a specific country, using its 2 letter alpha-2 code e.g FR, DE, HN +Get all ISO 3166-2 subdivision data for a specific country, using its 2 letter alpha-2 code e.g FR, DE, HN ---------------------------------------------------------------------------------------------------------- ### Request @@ -79,9 +77,9 @@ Get all country and ISO 3166-2 data for a specific country, using its 2 letter a content-type: application/json date: Tue, 20 Dec 2022 17:30:27 GMT server: Vercel - content-length: 4513 + content-length: 26298 - {"FR":[{"altSpellings":"", "area": "", "borders": ""...}]} + {"FR":{"FR-01":{...}}} ### Request `GET /api/alpha2/DE` @@ -93,9 +91,9 @@ Get all country and ISO 3166-2 data for a specific country, using its 2 letter a content-type: application/json date: Tue, 20 Dec 2022 17:31:19 GMT server: Vercel - content-length: 10 + content-length: 3053 - {"DE":[{"altSpellings":"", "area": "", "borders": ""...}]} + {"DE":{"DE-BB":{...}}} ### Request `GET /api/alpha2/HN` @@ -107,9 +105,9 @@ Get all country and ISO 3166-2 data for a specific country, using its 2 letter a content-type: application/json date: Tue, 20 Dec 2022 17:31:53 GMT server: Vercel - content-length: 479 + content-length: 2708 - {"HN":[{"altSpellings":"", "area": "", "borders": ""...}]} + {"HN":{"HN-AT":{...}}} ### Python ```python @@ -138,7 +136,7 @@ function getData() { var data = JSON.parse(this.response) ``` -Get all country and ISO 3166-2 data for a specific country, using country name, e.g. Tajikistan, Seychelles, Uganda +Get all ISO 3166-2 subdivision data for a specific country, using country name, e.g. Tajikistan, Seychelles, Uganda ------------------------------------------------------------------------------------------------------------------- ### Request @@ -151,9 +149,9 @@ Get all country and ISO 3166-2 data for a specific country, using country name, content-type: application/json date: Tue, 20 Dec 2022 17:40:19 GMT server: Vercel - content-length: 10 + content-length: 701 - {"TJ":[{"altSpellings":"", "area": "", "borders": ""...}]} + {"TJ":{"TJ-DU":{...}}} ### Request `GET /api/name/Seychelles` @@ -165,9 +163,9 @@ Get all country and ISO 3166-2 data for a specific country, using country name, content-type: application/json date: Tue, 20 Dec 2022 17:41:53 GMT server: Vercel - content-length: 479 + content-length: 5085 - {"SC":[{"altSpellings":"", "area": "", "borders": ""...}]} + {"SC":{"SC-01":{...}}} ### Request `GET /api/name/Uganda` @@ -179,9 +177,9 @@ Get all country and ISO 3166-2 data for a specific country, using country name, content-type: application/json date: Tue, 21 Dec 2022 19:43:19 GMT server: Vercel - content-length: 10 + content-length: 14965 - {"UG":[{"altSpellings":"", "area": "", "borders": ""...}]} + {"UG":{"UG-101":{...}}} ### Python ```python @@ -210,81 +208,6 @@ function getData() { var data = JSON.parse(this.response) ``` -Get area, population and timezones attributes for a specific country, using its 2 letter alpha-2 code e.g LA, PA, RO --------------------------------------------------------------------------------------------------------------------- - -### Request -`GET /api/alpha2/LA?filter=area,population,timezones` - - curl -i https://iso3166-2-api.vercel.app/api/alpha2/LA?filter=area,population,timezones - -### Response - HTTP/2 200 - content-type: application/json - date: Sat, 23 Sep 2023 12:56:44 GMT - server: Vercel - content-length: 70 - - {"LA":{"area":236800,"population":7275556,"timezones":["UTC+07:00"]}} - -### Request -`GET /api/alpha2/PA?filter=area,population,timezones` - - curl -i https://iso3166-2-api.vercel.app/api/alpha2/PA?filter=area,population,timezones - -### Response - HTTP/2 200 - content-type: application/json - date: Sat, 23 Sep 2023 12:57:34 GMT - server: Vercel - content-length: 70 - - {"PA":{"area":75417,"population":4314768,"timezones":["UTC-05:00"]}} - -### Request -`GET /api/alpha2/RO` - - curl -i https://iso3166-2-api.vercel.app/api/alpha2/RO?filter=area,population,timezones - -### Response - HTTP/2 200 - content-type: application/json - date: Sat, 23 Sep 2023 12:58:54 GMT - server: Vercel - content-length: 71 - - {"RO":{"area":238391,"population":19286123,"timezones":["UTC+02:00"]}} - -### Python -```python -import requests - -base_url = "https://iso3166-2-api.vercel.app/api/" -input_alpha2 = "LA" #PA, RO - -request_url = base_url + f"alpha2/{input_alpha2}" - -all_request = requests.get(request_url, params={"filter": "area,population,timezones"}) -all_request.json() -``` - -### Javascript -```javascript -let input_alpha2 = "LA"; //PA, RO - -function getData() { - const response = - await fetch(`https://iso3166-updates.com/api/alpha2/${input_alpha2}` + - new URLSearchParams({ - filter: "area,population,timezones" - })); - const data = await response.json() -} - -// Begin accessing JSON data here -var data = JSON.parse(this.response) -``` - [Back to top](#TOP) [attributes]: https://github.com/amckenna41/iso3166-2-api/ATTRIBUTES.md diff --git a/ATTRIBUTES.md b/ATTRIBUTES.md index a352202..669f833 100644 --- a/ATTRIBUTES.md +++ b/ATTRIBUTES.md @@ -1,54 +1,8 @@ | Field | Info | |------------------------|------| -| altSpellings / altNames | Alternate spellings and names of country name | -| area | Geographical size (km^2) | -| borders | Border countries | -| capital | Capital city/cities | -| capitalInfo > latlng | Capital city latitude and longitude | -| car > side | Car driving side | -| car > signs | Car distinguised (oval) signs | -| cca2 / alpha2Code | ISO 3166-1 alpha-2 two-letter country code | -| cca3 / alpha3Code | ISO 3166-1 alpha-3 three-letter country code | -| ccn3 / numericCode | ISO 3166-1 numeric code (UN M49) | -| cioc | Code of the International Olympic Committee | -| coatOfArms > png | [MainFacts.com](https://mainfacts.com/coat-of-arms-countries-world) link to png of country's coat of arms | -| coatOfArms > svg | [MainFacts.com](https://mainfacts.com/coat-of-arms-countries-world) link to svg of country's coat of arms | -| continents | List of continents the country is on | -| currencies > name | List of country's currency names | -| currencies > symbol | List of country's currency's international symbol | -| demonym | Name for the inhabitants of the country | -| demonyms > m/f | Genderized inhabitants of the country in English and native languages | -| fifa | FIFA code | -| flag | Unicode flag emoji (https://flagpedia.net/emoji)| -| flags > alt | Image alt text description for flag | -| flags > png | [Flagpedia](https://flagpedia.net/) link to png of country flag | -| flags > svg | [Flagpedia](https://flagpedia.net/) link to svg of country flag | -| gini | Worldbank [Gini](https://data.worldbank.org/indicator/SI.POV.GINI) index | -| idd > root | International dialing/calling code root | -| idd > suffix | International dialing/calling code suffix | -| independent | ISO 3166-1 independence status (the country is considered a sovereign state) | -| landlocked | Landlocked country (true/false) | -| languages | List of official languages | -| latlng | Latitude and longitude | -| maps > googleMaps | Link to country on Google Maps | -| maps > openStreetMaps | Link to country on Open Street Maps | -| name > common | Common country name in English | -| name > nativeName | Native country name | -| name > nativeName > official/common | Official and common country name in native language | -| name > official | Official country name | -| population | Country population | -| postalCodes > format/regex | Country postal code format | -| region | UN [demographic regions](https://unstats.un.org/unsd/methodology/m49/) | -| startOfWeek | Day of the start of week (Sunday/Monday) | -| status | ISO 3166-1 assignment status | -| subdivisions | List of a country's [ISO3166-2](https://en.wikipedia.org/wiki/ISO_3166-2) subdivision names and codes | -| subdivisions > flag_url | URL to subdivision's flag on [iso3166-flag-icons](https://github.com/amckenna41/iso3166-flag-icons) repo, if applicable | -| subdivisions > latlng | Coordinates for subdivision, using the Google Maps API | -| subdivisions > name | Name of subdivision | -| subdivisions > parent_code | Parent code of subdivision | -| subdivisions > type | Parent code of subdivision | -| subregion | UN [demographic subregions](https://unstats.un.org/unsd/methodology/m49/) | -| timezones | Timezones | -| tld / topLevelDomain | Internet top level domain | -| translations > official/common | List of official and common country name in translated languages | -| unMember | UN Member status | \ No newline at end of file + +| flag_url | URL to subdivision's flag on [iso3166-flag-icons](https://github.com/amckenna41/iso3166-flag-icons) repo, if applicable | +| latlng | Coordinates for subdivision, using the Google Maps API | +| name | Name of subdivision | +| parent_code | Parent code of subdivision | +| type | Subdivision type | \ No newline at end of file diff --git a/README.md b/README.md index c6f5a65..f6c0af3 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ iso -> Frontend API for the iso3166-2 repo that returns a plethora of data fields for all countries in the ISO 3166-1 and ISO 3166-2 standards. Utilising the restcountries API (https://restcountries.com/) as well as the custom-built [`iso3166-2`](https://github.com/amckenna41/iso3166-2) software that incorporates additional subdivision/regional data from the ISO 3166-2. Built using the Python [Flask][flask] framework and hosted on the [Vercel][vercel] platform. A demo of the API and the Python package are available [here][demo]. +> Frontend API for the iso3166-2 repo that returns a plethora of subdivision data for all countries in the ISO 3166-2 standard. Utilising the custom-built [`iso3166-2`](https://github.com/amckenna41/iso3166-2) software that incorporates subdivision/regional data from the ISO 3166-2. Built using the Python [Flask][flask] framework and hosted on the [Vercel][vercel] platform. A demo of the API and the Python package are available [here][demo]. The main API homepage and documentation is available via the URL: @@ -30,9 +30,9 @@ Table of Contents Introduction ------------ -This repo contains the front and backend of the API created for the [`iso3166-2`](https://github.com/amckenna41/iso3166-2) repository. The API returns a plethora of data fields for all countries in the ISO 3166-1 and ISO 3166-2 standards. Utilising the [RestCountries API](https://restcountries.com/) as well as the custom-built [`iso3166-2`](https://github.com/amckenna41/iso3166-2) software that incorporates data from the ISO 3166-2. Built using the Python [Flask][flask] framework and hosted on the [Vercel][vercel] platform. +This repo contains the front and backend of the API created for the [`iso3166-2`](https://github.com/amckenna41/iso3166-2) repository. The API returns a plethora of subdivison data for all countries in the ISO 3166-2 standard. Utilising the custom-built [`iso3166-2`](https://github.com/amckenna41/iso3166-2) software that incorporates data from the ISO 3166-2. Built using the Python [Flask][flask] framework and hosted on the [Vercel][vercel] platform. -[`iso3166-2`](https://github.com/amckenna41/iso3166-2) is a lightweight custom-built Python wrapper for RestCountries API (https://restcountries.com/) which includes an abundance of information about all ISO 3166 countries. But this package also includes information about all countrys' ISO 3166-2 subdivision codes & names, which is absent from RestCountries. Here, subdivision can be used interchangably with regions/states/provinces etc. The full list of additional subdivision data attributes supported are: +[`iso3166-2`](https://github.com/amckenna41/iso3166-2) is a lightweight custom-built Python wrapper that includes information about all countrys' ISO 3166-2 subdivision codes & names. Here, subdivision can be used interchangably with regions/states/provinces etc. The full list of additional subdivision data attributes supported are: * Name * Code * Parent Code @@ -53,27 +53,27 @@ The other endpoints available in the API are: * https://iso3166-2-api.vercel.app/api/alpha2/ * https://iso3166-2-api.vercel.app/api/name/ -Three paths/endpoints are available in the API - `/api/all`, `/api/alpha2` and `/api/name`. +Three paths/endpoints are available in the API - `/api/all`, `/api/alpha2` and `/api/name`. -* The `/api/all` path/endpoint returns all of the ISO 3166 country data for all countries (due to the size of the object this can take some time to load). +* The `/api/all` path/endpoint returns all of the ISO 3166 subdivision data for all countries. -* The 2 letter alpha-2 country code can be appended to the **alpha2** path/endpoint e.g /api/alpha2/JP. A single alpha-2 or list of them can be passed to the endpoint e.g /api/alpha2/FR,DE,HU,ID,MA. For redundancy, the 3 letter alpha-3 counterpart for each country's alpha-2 code can also be appended to the path e.g /api/alpha2/FRA,DEU,HUN,IDN,MAR. If an invalid alpha-2 code is input then an error will be returned. +* The 2 letter alpha-2 country code can be appended to the **alpha2** path/endpoint e.g /api/alpha2/JP. A single alpha-2 or list of them can be passed to the API e.g /api/alpha2/FR,DE,HU,ID,MA. For redudancy, the 3 letter alpha-3 counterpart for each country's alpha-2 code can also be appened to the path e.g /api/alpha2/FRA,DEU,HUN,IDN,MAR. If an invalid alpha-2 code is input then an error will be returned. -* The name parameter can be a country name as it is most commonly known in english, according to the ISO 3166-1. The name can similarly be appended to the **name** path/endpoint e.g /api/name/Denmark. A single country name or list of them can be passed into the endpoint e.g /api/name/France,Moldova,Benin. A closeness function is utilised so that the most approximate name from the input will be used e.g Sweden will be used if the input is /api/name/Swede. If no country is found from the closeness function or an invalid name is input then an error will be returned. +* The name parameter can be a country name as it is most commonly known in english, according to the ISO 3166-1. The name can similarly be appended to the **name** path/endpoint e.g /api/name/Denmark. A single country name or list of them can be passed into the API e.g /name/France,Moldova,Benin. A closeness function is utilised so the most approximate name from the input will be used e.g Sweden will be used if /api/name/Swede. If no country is found from the closeness function or an invalid name is input then an error will be returned. * The main API endpoint (`/` or `/api`) will return the homepage and API documentation. -The `filter` query string parameter can be appended to any of the endpoints. It accepts a string of one or more attributes that the user wants to only be returned from their request e.g /api/alpha2/IE?filter=capital,currencies,languages,region. This example means that only the capital city, currencies, languages and region data for Ireland will be returned. If an invalid attribute name is input then it will be removed from the request. - The full list of attributes available for each country are available in the [ATTRIBUTES.md][attributes] file. -The API documentation and usage with all useful commands and examples to the API is available on the [API.md][api_md] file. A demo of the software and API is also available [here][demo]. +The API documentation and usage with all useful commands and examples to the API is available on the [API.md][api_md] file. A demo of the software and API are available [here][demo]. Staying up to date ------------------ -The ISO is a very dynamic organisation and regularly change/update/remove entries within its library of standards, including the ISO 3166. Additions/changes/deletions to country/territorial codes and attributes vary and update occassioanlly. On the main [`iso3166-2`](https://github.com/amckenna41/iso3166-2) repo a Cloud Function is periodically called periodically that pulls all the latest data and attributes for all ISO 3166 countries, ultimately updating the backend JSON file that the iso3166-2-api uses. This ensures that the object and its data stay up-to-date and accurate. +The ISO is a very dynamic organisation and regularly change/update/remove entries within its library of standards, including the ISO 3166. Additions/changes/deletions to country/territorial codes and attributes vary and update occassioanlly. On the main [`iso3166-2`](https://github.com/amckenna41/iso3166-2) repo a Cloud Function is periodically called periodically that pulls all the latest subdivision data and attributes for all ISO 3166 countries, ultimately updating the backend JSON file that the iso3166-2-api uses. This ensures that the object and its data stay up-to-date and accurate. + +Additionally, as the software and API include data from the ISO 3166-2 which includes country subdivison codes and data, a custom-built software [`iso3166-updates`](https://github.com/amckenna41/iso3166-updates) was created. Compared to the ISO 3166-1, changes are more frequent for the ISO 3166-2 codes due to there being thousands more entries, thus it can be difficult to keep up with any changes to these codes. These changes can occur for a variety of geopolitical and administrative reasons and are usually communicated via Newsletters on the ISO platform, their Online Browsing Platform (OBP) or via a database, which usually costs money to subscribe to [[3]](#references). Usually these updates are conveyed at the end of the year, with amendments and updates occasionally published at various times throughout the year [[4]](#references). -Additionally, as the software and API include data from the ISO 3166-2 which includes country subdivison codes and data, a custom-built software [`iso3166-updates`](https://github.com/amckenna41/iso3166-updates) was created. Compared to the ISO 3166-1, changes are more frequent for the ISO 3166-2 codes due to there being thousands more entries, thus it can be difficult to keep up with any changes to these codes. These changes can occur for a variety of geopolitical and bureaucratic reasons and are usually communicated via Newsletters on the ISO platform, their Online Browsing Platform (OBP) or via a database, which usually costs money to subscribe to [[3]](#references). Usually these updates are conveyed at the end of the year, with amendments and updates occasionally published at various times throughout the year [[4]](#references). The [`iso3166-updates`](https://github.com/amckenna41/iso3166-updates) software tracks and maintain these changes/updates that are made. The software and accompanying API (https://iso3166-updates.com) makes it extremely easy to check for any new or historic updates to a country or set of country's ISO 3166-2 codes for free, with an easy-to-use interface and Python package and API, ensuring that you get the most up-to-date and accurate ISO 3166-2 codes and naming conventions. A custom script is run periodically (every 3-6 months) that uses the [`iso3166-updates`](https://github.com/amckenna41/iso3166-updates) software to check for any updates. If updates are found then a GitHub Issue is automatically raised on the `iso3166-2` repository, communicating all updates/changes that need to be implemented into the `iso3166-2` repo's software and JSONs. +The [`iso3166-updates`](https://github.com/amckenna41/iso3166-updates) software tracks and maintain these changes/updates that are made. The software and accompanying API (https://iso3166-updates.com) make it extremely easy to check for any new or historic updates to a country or set of country's ISO 3166-2 codes for free, with an easy-to-use interface and Python package and API, ensuring that you get the most up-to-date and accurate ISO 3166-2 codes and naming conventions. A custom script is run periodically (every 3-6 months) that uses the [`iso3166-updates`](https://github.com/amckenna41/iso3166-updates) software to check for any updates. If updates are found then a GitHub Issue is automatically raised on the `iso3166-2` repository, communicating all updates/changes that need to be implemented into the `iso3166-2` repo's software and JSONs. Requirements ------------ diff --git a/ToDo.md b/ToDo.md index d6cdb60..a0b7eb8 100644 --- a/ToDo.md +++ b/ToDo.md @@ -35,7 +35,16 @@ - [X] Further highlight the addition of subdivion-related data etc in reamde and demo. - [X] Mention in readme and iso3166-2 readme that "subdivision can be used interachangably with states/regions/provinces etc". - [X] Mention that the library contains the flag info for each - from iso3166-flag-icons repo. +- [X] Pass in nested dict of attribute filter values to API: https://stackoverflow.com/questions/73800401/how-to-send-nested-dictionary-as-params-in-python-requests-get. E.g https://iso3166-2-api-amckenna41.vercel.app/api/all?filter=%7Bindependent:true%7D +- [X] Add more filter attribute unit tests for when dict of keys/vals passed in. +- [X] Not working: https://iso3166-2-api-amckenna41.vercel.app/api/alpha2/DK?filter=capital - returns {}. +- [X] Add nested dict of filter attribute values but allow for gt/lt or range of values to be input/returned - area and population - add unit tests. +- [X] Split up 'filter' section in api.md into 3 sections. +- [X] Add app.url_map.strict_slashes = False +- [X] Update comments to include v1/v2. Future Additions ---------------- -- [ ] /list endpoint that returns list of all codes and their names. \ No newline at end of file +- [ ] /list endpoint that returns list of all codes and their names. +- [ ] Create frontend with jsvectormap +- [ ] Add population & area per subdivision. \ No newline at end of file diff --git a/index.py b/index.py index 4a16d7f..5e446b1 100644 --- a/index.py +++ b/index.py @@ -10,6 +10,9 @@ #initialise Flask app app = Flask(__name__) +#register routes/endpoints with or without trailing slash +app.url_map.strict_slashes = False + #get Cloud Storage specific env vars sa_json_str = os.environ["SA_JSON"] project_id = os.environ["PROJECT_ID"] @@ -48,7 +51,8 @@ @app.route('/') @app.route('/api') -@app.route('/api/') +@app.route('/api/v1') +@app.route('/api/v2') def home(): """ Default route for https://iso3166-2-api.vercel.app/. Main homepage for API displaying the @@ -65,15 +69,12 @@ def home(): """ return render_template('index.html') -@app.route('/all', methods=['GET']) -@app.route('/all/', methods=['GET']) +@app.route('/v1/all', methods=['GET']) @app.route('/api/all', methods=['GET']) -@app.route('/api/all/', methods=['GET']) -def all(): +def all_v1(): """ - Flask route for '/api/all' path/endpoint. Return all ISO 3166-2 data for all countries. This - path can take some time to load due to the large amount of ISO 3166 data. Route can accept - path with or without trailing slash. + Flask route for '/api/all' path/endpoint. Return all ISO 3166-2 subdivision data attributes and + values for all countries. Route can accept path with or without trailing slash. Parameters ========== @@ -82,25 +83,26 @@ def all(): Returns ======= :jsonify(all_iso3166_2) : json - jsonified ISO 3166-2 data. + jsonified version 1 ISO 3166-2 subdivision data. :status_code : int response status code. 200 is a successful response, 400 means there was an invalid parameter input. """ - #return error if blob not found in bucket, else return all ISO 3166-2 data + #return error if blob not found in bucket, else return all ISO 3166-2 subdivision data if not (blob_exists): return jsonify(blob_not_found_error_message), 400 + return jsonify(all_iso3166_2), 200 @app.route('/api/name/', methods=['GET']) -@app.route('/api/name//', methods=['GET']) +@app.route('/name/', methods=['GET']) def api_name(name): """ - Flask route for 'api/name' path/endpoint. Return all ISO 3166-2 data for inputted country - name/names. A closeness function is used on the input country name to get the closest match, - to a high degree, from the list of available countries, e.g if Swede is input then the data - for Sweden will be returned. Return error if invalid country name input. Route can accept - path with or without trailing slash. + Flask route for 'api/name' path/endpoint. Return all ISO 3166-2 subdivision data attributes and + values for inputted country name/names. A closeness function is used on the input country name + to get the closest match, to a high degree, from the list of available countries, e.g if Swede + is input then the data for Sweden will be returned. Return error if invalid country name input. + Route can accept path with or without trailing slash. Parameters ========== @@ -215,22 +217,17 @@ def api_name(name): for code in alpha2_code: iso3166_2[code] = all_iso3166_2[code] - #filter object to include only attributes specified by 'filter' query parameter, if applicable - iso3166_2 = filter_attributes(iso3166_2) - return jsonify(iso3166_2), 200 @app.route('/api/alpha2/', methods=['GET']) -@app.route('/api/alpha2//', methods=['GET']) +@app.route('/api/', methods=['GET']) @app.route('/alpha2/', methods=['GET']) -@app.route('/alpha2//', methods=['GET']) -@app.route('/api//', methods=['GET']) -def api_alpha2(alpha2): +def api_alpha2_v1(alpha2): """ - Flask route for '/api/alpha2' path/endpoint. Return all ISO 3166-2 data for the inputted alpha-2 - code/codes. If invalid alpha-2 code or no value input then return error. The endpoint can also - accept a country in its 3 letter alpha-3 code form, which will then be converted into its 2 letter - alpha-2 counterpart. Route can accept path with or without trailing slash. + Flask route for '/api/alpha2' path/endpoint. Return all version 1 ISO 3166-2 subdivision data for + the inputted alpha-2 code/codes. If invalid alpha-2 code or no value input then return error. The + endpoint can also accept a country in its 3 letter alpha-3 code form, which will then be converted + into its 2 letter alpha-2 counterpart. Route can accept path with or without trailing slash. Parameters ========== @@ -326,9 +323,6 @@ def convert_to_alpha2(alpha3_code): for code in alpha2_code: iso3166_2[code] = all_iso3166_2[code] - #filter object to include only attributes specified by 'filter' query parameter, if applicable - iso3166_2 = filter_attributes(iso3166_2) - return jsonify(iso3166_2), 200 @app.errorhandler(404) @@ -350,57 +344,6 @@ def not_found(e): """ return render_template("404.html", path=request.url), 404 -def filter_attributes(iso3166_2): - """ - Filter ISO 3166 object to just contain the sought attributes listed in the 'filter' - query string parameter. If query parameter not specified then return object as is. - Return error if invalid attribute name input. - - Parameters - ========== - :iso3166_2 : dict - unfiltered object containing all the ISO 3166 data for inputted county/countries. - - Returns - ======= - :filtered_iso3166_2 : dict - filtered object containing all the ISO 3166 data for inputted county/countries. If - attributes parameter input and valid then filter all other attributes out. - """ - #filtered object to contain filtered attributes data - filtered_iso3166_2 = {} - - #get attributes value from query string parameter - attributes = request.args.get('filter') - - #return original unfiltered data object if parameter value is None - if (attributes is None): - return iso3166_2 - - #split attributes into comma seperated list - attributes = attributes.replace(' ', '').split(',') - - #get correct attribute list from original json - attribute_list = list(iso3166_2[next(iter(iso3166_2))].keys()) - - #remove attribute from input list if invalid - for attr in attributes: - if not (attr in attribute_list): - attributes.remove(attr) - - #return original object if no attributes present after validation - if (attributes == []): - return iso3166_2 - - #iterate through alpha-2 codes in object, filter out attributes not specified in query parameter, if applicable - for code in iso3166_2: - filtered_iso3166_2[code] = {} - for key in iso3166_2[code]: - if (key in attributes): - filtered_iso3166_2[code][key] = iso3166_2[code][key] - - return filtered_iso3166_2 - if __name__ == '__main__': #run Flask app app.run(debug=True) \ No newline at end of file diff --git a/static/README.md b/static/README.md index fd78bc2..1f8d9ca 100644 --- a/static/README.md +++ b/static/README.md @@ -1,7 +1,7 @@ # Static files for API frontend -* `style.css` - main CSS for index and 404 html pages. -* `highlightjs-dark.css` - CSS for hl1js. -* `script.js` - main javascript file for index and 404 html pages. -* `iso-logo.svg` - ISO logo. -* `copy-icon.svg` - copy icon logo. \ No newline at end of file +* `css/style.css` - main CSS for index and 404 html pages. +* `css/highlightjs-dark.css` - CSS for hl1js. +* `js/script.js` - main javascript file for index and 404 html pages. +* `images/iso-logo.svg` - ISO logo. +* `images/copy-icon.svg` - copy icon logo. \ No newline at end of file diff --git a/static/js/script.js b/static/js/script.js index 548752d..63804d2 100644 --- a/static/js/script.js +++ b/static/js/script.js @@ -114,8 +114,6 @@ window.onload = function(){ let copyTextBtn1 = document.querySelector("#copy-text-btn1"); let copyTextBtn2 = document.querySelector("#copy-text-btn2"); let copyTextBtn3 = document.querySelector("#copy-text-btn3"); - let copyTextBtn4 = document.querySelector("#copy-text-btn4"); - let copyTextBtn5 = document.querySelector("#copy-text-btn5"); copyTextBtn1.addEventListener("click", function () { let apiURL = copyTextBtn1.getAttribute('data-api-url') @@ -134,16 +132,4 @@ window.onload = function(){ navigator.clipboard.writeText(apiURL); console.log('API URL copied to clipboard: ' + apiURL); }); - - copyTextBtn4.addEventListener("click", function () { - let apiURL = copyTextBtn4.getAttribute('data-api-url') - navigator.clipboard.writeText(apiURL); - console.log('API URL copied to clipboard: ' + apiURL); - }); - - copyTextBtn5.addEventListener("click", function () { - let apiURL = copyTextBtn5.getAttribute('data-api-url') - navigator.clipboard.writeText(apiURL); - console.log('API URL copied to clipboard: ' + apiURL); - }); -} +} \ No newline at end of file diff --git a/templates/index.html b/templates/index.html index 19f6f2a..25c0430 100644 --- a/templates/index.html +++ b/templates/index.html @@ -18,7 +18,7 @@ - + @@ -44,9 +44,9 @@
@@ -71,12 +70,10 @@

About

- The ISO 3166-2 API is a custom-built, open-source and free to use RESTful API that provides programmatic access to a plethora of data attributes for all ISO 3166 countries/territories. - The project was inspired by Rest Countries but includes additional subdivison/regional related data from the ISO 3166-2 of each country. Built - using the Python Flask framework and hosted on the Vercel platform.

A demo of the API and Python software are available - here.
Source code available here.

- - + The ISO 3166-2 API is a custom-built, open-source and free to use RESTful API that provides programmatic access to a plethora of subdivision data attributes for all ISO 3166-2 countries/territories. + For each country, the API returns its subdivision names, codes, types, parent codes, latitude/longitude and flag, where applicable. +

A demo of the API and Python software are available here.
+ Source code available here.

@@ -85,7 +82,7 @@

About

Attributes

The list of data attributes supported by the API, along with a description of each can be viewed in the - ATTRIBUTES.md file on the repository. + ATTRIBUTES.md file on the repository.

@@ -107,20 +104,20 @@

Endpoints

https://iso3166-2-api.vercel.app/api/all - Return all data attributes for all countries in the ISO 3166 (this takes a little time for the page to load due to the large amount of data). + Return all suddivision data attributes for all countries in the ISO 3166-2. https://iso3166-2-api.vercel.app/api/alpha2/{input_alpha2} - Return all data attributes for country with matching 2 letter alpha-2 country code. A comma seperated + Return all subdivision data attributes for country/countries with matching 2 letter alpha-2 country code. A comma seperated list of country codes can also be input. For redundancy the 3 letter alpha-3 code can also be accepted as input. https://iso3166-2-api.vercel.app/api/name/{input_name} - Return all data attributes for input country name, as it is commonly known in English. A comma seperated list of country names can also be input. + Return all subdivision data attributes for input country name, as it is commonly known in English. A comma seperated list of country names can also be input. @@ -131,11 +128,10 @@

Endpoints

all

- The /all endpoint returns all the data attribute values for all ISO 3166 countries. The list of countries supported is according to the - ISO 3166-1 standard. This endpoint can take a little time to load - and return a response due to the large amount of data.

+ The /all endpoint returns all the subdivision data attribute values for all ISO 3166-2 countries. The list of countries supported is according to the + ISO 3166-1 standard.

https://iso3166-2-api.vercel.app/api/all - +

@@ -143,10 +139,10 @@

all

alpha-2

- The /alpha2 endpoint returns all the data attribute values for the country with the matching 2 letter alpha-2 country code. A comma seperated + The /alpha2 endpoint returns all the subdivision data attribute values for the country with the matching 2 letter alpha-2 country code. A comma seperated list of country codes can also be input. For redundancy the 3 letter alpha-3 code can also be accepted as input.

https://iso3166-2-api.vercel.app/api/alpha2/{alpha2} -

+

https://iso3166-2-api.vercel.app/api/alpha2/AD
https://iso3166-2-api.vercel.app/api/alpha2/DE
https://iso3166-2-api.vercel.app/api/alpha2/ZA @@ -157,37 +153,21 @@

alpha-2

name

- The /name endpoint returns all the data attribute values for a country according to its name as it is commonly known in English. A comma + The /name endpoint returns all the subdivision data attribute values for a country according to its name as it is commonly known in English. A comma seperated list of country names can also be input.

https://iso3166-2-api.vercel.app/api/name/{name} -

+

https://iso3166-2-api.vercel.app/api/name/Ireland
https://iso3166-2-api.vercel.app/api/name/Jamaica
https://iso3166-2-api.vercel.app/api/name/Panama,Rwanda,Zambia

- -
-

Filter Output

-

- The output of an API request can be filtered to include only the sought attributes for the input country/countries. To do this, append the 'filter' - query string parameter to the API URL at any of the above endpoints and pass in a list of one or more attribute names. The full list of attributes - available in the API can be viewed on the ATTRIBUTES.md file on - the repository.

- https://iso3166-2-api.vercel.app/api/alpha2/{alpha2}?filter={attribute},{attribute},{attribute} -

- https://iso3166-2-api.vercel.app/api/alpha2/FR?filter=name,languages,region
- https://iso3166-2-api.vercel.app/api/name/Namibia?filter=continents,fifa,timezones
- https://iso3166-2-api.vercel.app/api/all?filter=gini,landlocked,startOfWeek -

-
-

Credits

- The Python software and accompanying API were solely developed by me : ). + The Python software and accompanying API were solely developed by me : ).

@@ -195,13 +175,13 @@

Credits

Contributing

- Contributions, enhancements or feedback to the software and or API are more than welcome! You can raise an Issue or make a pull request on the GitHub Repo or + Contributions, enhancements or feedback to the software and or API are more than welcome! You can raise an Issue or make a pull request on the GitHub Repo or email amckenna41@qub.ac.uk.

- + \ No newline at end of file diff --git a/tests/test_iso3166_2_api.py b/tests/test_iso3166_2_api.py index 04ced96..b9723fe 100644 --- a/tests/test_iso3166_2_api.py +++ b/tests/test_iso3166_2_api.py @@ -1,6 +1,8 @@ import iso3166 import requests import getpass +import os +from importlib.metadata import metadata from bs4 import BeautifulSoup import unittest unittest.TestLoader.sortTestMethodsUsing = None @@ -19,15 +21,12 @@ class ISO3166_2_API_Tests(unittest.TestCase): testing correct objects are returned from /name API endpoint using a variety of inputs. test_all_endpoint: testing correct objects are returned from /name API endpoint, which returns all the available - ISO 3166-2 data. - test_filter_output: - testing filter_attributes function that filters output object to include only sought after - attributes. + ISO 3166-2 data. """ def setUp(self): """ Initialise test variables, import json. """ #initalise User-agent header for requests library - self.__version__ = "1.1.0" + self.__version__ = metadata('iso3166-2')['version'] self.user_agent_header = {'User-Agent': 'iso3166-2/{} ({}; {})'.format(self.__version__, 'https://github.com/amckenna41/iso3166-2', getpass.getuser())} @@ -38,17 +37,12 @@ def setUp(self): self.name_base_url = self.api_base_url + "name/" self.all_base_url = self.api_base_url + "all" - #list of output columns for main iso3166-2 json - self.correct_output_cols = [ - "altSpellings", "area", "borders", "capital", "capitalInfo", "car", "cca2", "cca3", "ccn3", "cioc", "coatOfArms", - "continents", "currencies", "demonyms", "fifa", "flag", "flags", "gini", "idd", "independent", "landlocked", - "languages", "latlng", "maps", "name", "population", "postalCode", "region", "startOfWeek", "status", - "subdivisions", "subregion", "timezones", "tld", "translations", "unMember" - ] - #list of keys that should be in subdivisions key of output object self.correct_subdivision_keys = ["flag_url", "latlng", "name", "parent_code", "type"] + #base url for subdivision flag icons + self.flag_base_url = "https://github.com/amckenna41/iso3166-flag-icons/blob/main/iso3166-2-icons/" + def test_homepage_endpoint(self): """ Testing contents of main "/api" endpoint that returns the homepage and API documentation. """ test_request_main = requests.get(self.api_base_url, headers=self.user_agent_header) @@ -58,183 +52,197 @@ def test_homepage_endpoint(self): last_updated = soup.find(id='last-updated').text.split(': ')[1] author = soup.find(id='author').text.split(': ')[1] - self.assertEqual(version, "1.2.1", "Expected API version to be 1.2.1, got {}.".format(version)) + self.assertEqual(version, "1.3.0", "Expected API version to be 1.3.0, got {}.".format(version)) self.assertEqual(last_updated, "October 2023", "Expected last updated data to be October 2023, got {}.".format(last_updated)) self.assertEqual(author, "AJ", "Expected author to be AJ, got {}.".format(author)) #2.) section_list_menu = soup.find(id='section-list-menu').find_all('li') - correct_section_menu = ["About", "Attributes", "Endpoints", "All", "Alpha-2 Code", "Name", "Filter Output", "Credits", "Contributing"] + correct_section_menu = ["About", "Attributes", "Endpoints", "All", "Alpha-2 Code", "Name", "Credits", "Contributing"] for li in section_list_menu: self.assertIn(li.text.strip(), correct_section_menu, "Expected list element {} to be in list.".format(li)) - + def test_alpha2_endpoint(self): """ Testing alpha-2 endpoint, return all ISO 3166 data from input alpha-2 code/codes. """ test_alpha2_au = "AU" #Australia test_alpha2_cy = "CY" #Cyprus test_alpha2_lu = "LU" #Luxembourg test_alpha2_pa_rw = "PA, RW" #Panama, Rwanda - test_alpha2_mac_mys = "MAC, MYS" #Macau, Malaysia test_alpha2_error_1 = "ABCDE" test_alpha2_error_2 = "12345" #1.) - #for each alpha-2 code, test API returns correct object, test using cca2 attribute - for alpha2 in sorted(list(iso3166.countries_by_alpha2.keys())): - test_request_alpha2 = requests.get(self.alpha2_base_url + alpha2, headers=self.user_agent_header).json() - self.assertEqual(test_request_alpha2[alpha2]["cca2"], alpha2, - "Input alpha-2 code {} and one in output object do not match: {}.".format(alpha2, test_request_alpha2[alpha2]["cca2"])) -#2.) test_request_au = requests.get(self.alpha2_base_url + test_alpha2_au, headers=self.user_agent_header).json() #Australia self.assertIsInstance(test_request_au, dict, "Expected output object of API to be type dict, got {}.".format(type(test_request_au))) self.assertEqual(len(test_request_au), 1, "Expected output object of API to be of length 1, got {}.".format(len(test_request_au))) self.assertEqual(list(test_request_au.keys()), ["AU"], "Expected output object of API to contain only the AU key, got {}.".format(list(test_request_au.keys()))) - - self.assertEqual(test_request_au["AU"]["area"], 7692024, "Expected area to be 7692024, got {}.".format(test_request_au["AU"]["area"])) - self.assertEqual(test_request_au["AU"]["name"]["common"], "Australia", "Expected country name to be Australis, got {}.".format(test_request_au["AU"]["name"]["common"])) - self.assertEqual(test_request_au["AU"]["capital"][0], "Canberra", "") - self.assertEqual(test_request_au["AU"]["cca2"], "AU", "") - self.assertEqual(test_request_au["AU"]["cca3"], "AUS", "") - self.assertEqual(test_request_au["AU"]["currencies"]["AUD"]['name'], "Australian dollar", "") - self.assertEqual(list(test_request_au["AU"]["languages"].keys())[0], "eng", "") - self.assertEqual(test_request_au["AU"]["latlng"], [-27.0, 133.0], "") - self.assertEqual(test_request_au["AU"]["population"], 25687041, "") - self.assertEqual(test_request_au["AU"]["region"], "Oceania", "") - self.assertEqual(list(test_request_au["AU"]["subdivisions"].keys()), - ["AU-ACT", "AU-NSW", "AU-NT", "AU-QLD", "AU-SA", "AU-TAS", "AU-VIC", "AU-WA"], "") - for subd in test_request_au["AU"]["subdivisions"]: - for key in list(test_request_au["AU"]["subdivisions"][subd].keys()): - self.assertIn(key, self.correct_subdivision_keys, "Key {} not found in list of correct keys:\n{}.".format(key, self.correct_subdivision_keys)) - for col in list(test_request_au["AU"].keys()): - self.assertIn(col, self.correct_output_cols, "Column {} not found in list of correct columns:\n{}.".format(col, self.correct_output_cols)) -#3.) + self.assertEqual(list(test_request_au["AU"].keys()), ["AU-ACT", "AU-NSW", "AU-NT", "AU-QLD", "AU-SA", "AU-TAS", "AU-VIC", "AU-WA"], "Expected list of subdivision codes doesn't match output.") + for subd in test_request_au["AU"]: + self.assertIsNot(test_request_au["AU"][subd]["name"], None, + "Expected subdivision name to not be None, got {}.".format(test_request_au["AU"][subd]["name"])) + if not (test_request_au["AU"][subd]["flag_url"] is None): + self.assertEqual(os.path.splitext(test_request_au["AU"][subd]["flag_url"])[0], self.flag_base_url + "AU/" + subd, + "Expected flag url to be {}, got {}.".format(self.flag_base_url + "AU/" + subd, os.path.splitext(test_request_au["AU"][subd]["flag_url"])[0])) + self.assertEqual(requests.get(test_request_au["AU"][subd]["flag_url"], headers=self.user_agent_header).status_code, 200, + "Flag URL invalid: {}.".format(test_request_au["AU"][subd]["flag_url"])) + for key in list(test_request_au["AU"][subd].keys()): + self.assertIn(key, self.correct_subdivision_keys, "Attribute {} not found in list of correct attributes:\n{}.".format(key, self.correct_subdivision_keys)) + + #AU-NSW - New South Wales + self.assertEqual(test_request_au["AU"]["AU-NSW"]["name"], "New South Wales", + "Expected subdivsion name to be New South Wales, got {}.".format(test_request_au["AU"]["AU-NSW"]["name"])) + self.assertEqual(test_request_au["AU"]["AU-NSW"]["parent_code"], None, + "Expected subdivision parent code to be None, got {}.".format(test_request_au["AU"]["AU-NSW"]["parent_code"])) + self.assertEqual(test_request_au["AU"]["AU-NSW"]["type"], "State", + "Expected subdivision type to be State, got {}.".format(test_request_au["AU"]["AU-NSW"]["type"])) + self.assertEqual(test_request_au["AU"]["AU-NSW"]["latlng"], [-31.253, 146.921], + "Expected subdivision latlng to be [-31.253, 146.921], got {}.".format(test_request_au["AU"]["AU-NSW"]["latlng"])) + self.assertEqual(test_request_au["AU"]["AU-NSW"]["flag_url"], "https://github.com/amckenna41/iso3166-flag-icons/blob/main/iso3166-2-icons/AU/AU-NSW.svg", + "Expected subdivision flag url to be https://github.com/amckenna41/iso3166-flag-icons/blob/main/iso3166-2-icons/AU/AU-NSW.svg, got {}.".format(test_request_au["AU"]["AU-NSW"]["flag_url"])) + #AU-QLD - Queensland + self.assertEqual(test_request_au["AU"]["AU-QLD"]["name"], "Queensland", + "Expected subdivsion name to be Queensland, got {}.".format(test_request_au["AU"]["AU-QLD"]["name"])) + self.assertEqual(test_request_au["AU"]["AU-QLD"]["parent_code"], None, + "Expected subdivision parent code to be None got {}.".format(test_request_au["AU"]["AU-QLD"]["parent_code"])) + self.assertEqual(test_request_au["AU"]["AU-QLD"]["type"], "State", + "Expected subdivision type to be State, got {}.".format(test_request_au["AU"]["AU-QLD"]["type"])) + self.assertEqual(test_request_au["AU"]["AU-QLD"]["latlng"], [-22.575, 144.085], + "Expected subdivision latlng to be [-22.575, 144.085], got {}.".format(test_request_au["AU"]["AU-NSW"]["latlng"])) + self.assertEqual(test_request_au["AU"]["AU-QLD"]["flag_url"], "https://github.com/amckenna41/iso3166-flag-icons/blob/main/iso3166-2-icons/AU/AU-QLD.svg", + "Expected subdivision flag url to be https://github.com/amckenna41/iso3166-flag-icons/blob/main/iso3166-2-icons/AU/AU-QLD.svg, got {}.".format(test_request_au["AU"]["AU-QLD"]["flag_url"])) +#2.) test_request_cy = requests.get(self.alpha2_base_url + test_alpha2_cy, headers=self.user_agent_header).json() #Cyprus self.assertIsInstance(test_request_cy, dict, "Expected output object of API to be type dict, got {}.".format(type(test_request_cy))) self.assertEqual(len(test_request_cy), 1, "Expected output object of API to be of length 1, got {}.".format(len(test_request_cy))) self.assertEqual(list(test_request_cy.keys()), ["CY"], "Expected output object of API to contain only the CY key, got {}.".format(list(test_request_cy.keys()))) - - self.assertEqual(test_request_cy["CY"]["area"], 9251, "Expected area to be 9251, got {}.".format(test_request_cy["CY"]["area"])) - self.assertEqual(test_request_cy["CY"]["name"]["common"], "Cyprus", "") - self.assertEqual(test_request_cy["CY"]["capital"][0], "Nicosia", "") - self.assertEqual(test_request_cy["CY"]["cca2"], "CY", "") - self.assertEqual(test_request_cy["CY"]["cca3"], "CYP", "") - self.assertEqual(test_request_cy["CY"]["currencies"]["EUR"]['name'], "Euro", "") - self.assertEqual(list(test_request_cy["CY"]["languages"].keys()), ["ell", "tur"], "") - self.assertEqual(test_request_cy["CY"]["latlng"], [35, 33], "") - self.assertEqual(test_request_cy["CY"]["population"], 1207361, "") - self.assertEqual(test_request_cy["CY"]["region"], "Europe", "") - self.assertEqual(list(test_request_cy["CY"]["subdivisions"].keys()), - ["CY-01", "CY-02", "CY-03", "CY-04", "CY-05", "CY-06"], "") - for subd in test_request_cy["CY"]["subdivisions"]: - for key in list(test_request_cy["CY"]["subdivisions"][subd].keys()): - self.assertIn(key, self.correct_subdivision_keys, "Key {} not found in list of correct keys:\n{}.".format(key, self.correct_subdivision_keys)) - for col in list(test_request_cy["CY"].keys()): - self.assertIn(col, self.correct_output_cols, "Column {} not found in list of correct columns:\n{}.".format(col, self.correct_output_cols)) -#4.) + self.assertEqual(list(test_request_cy["CY"].keys()), ["CY-01", "CY-02", "CY-03", "CY-04", "CY-05", "CY-06"], "Expected list of subdivision codes doesn't match output.") + for subd in test_request_cy["CY"]: + self.assertIsNot(test_request_cy["CY"][subd]["name"], None, + "Expected subdivision name to not be None, got {}.".format(test_request_cy["CY"][subd]["name"])) + if not (test_request_cy["CY"][subd]["flag_url"] is None): + self.assertEqual(os.path.splitext(test_request_cy["CY"][subd]["flag_url"])[0], self.flag_base_url + "CY/" + subd, + "Expected flag url to be {}, got {}.".format(self.flag_base_url + "CY/" + subd, os.path.splitext(test_request_cy["CY"][subd]["flag_url"])[0])) + self.assertEqual(requests.get(test_request_cy["CY"][subd]["flag_url"], headers=self.user_agent_header).status_code, 200, + "Flag URL invalid: {}.".format(test_request_cy["CY"][subd]["flag_url"])) + for key in list(test_request_cy["CY"][subd].keys()): + self.assertIn(key, self.correct_subdivision_keys, "Attribute {} not found in list of correct attributes:\n{}.".format(key, self.correct_subdivision_keys)) + + #CY-01 - Lefkosia + self.assertEqual(test_request_cy["CY"]["CY-01"]["name"], "Lefkosia", + "Expected subdivsion name to be Lefkosia, got {}.".format(test_request_cy["CY"]["CY-01"]["name"])) + self.assertEqual(test_request_cy["CY"]["CY-01"]["parent_code"], None, + "Expected subdivision parent code to be None, got {}.".format(test_request_cy["CY"]["CY-01"]["parent_code"])) + self.assertEqual(test_request_cy["CY"]["CY-01"]["type"], "District", + "Expected subdivision type to be District, got {}.".format(test_request_cy["CY"]["CY-01"]["type"])) + self.assertEqual(test_request_cy["CY"]["CY-01"]["latlng"], [35.186, 33.382], + "Expected subdivision latlng to be [35.186, 33.382], got {}.".format(test_request_cy["CY"]["CY-01"]["latlng"])) + self.assertEqual(test_request_cy["CY"]["CY-01"]["flag_url"], "https://github.com/amckenna41/iso3166-flag-icons/blob/main/iso3166-2-icons/CY/CY-01.svg", + "Expected subdivision flag url to be https://github.com/amckenna41/iso3166-flag-icons/blob/main/iso3166-2-icons/CY/CY-01.svg, got {}.".format(test_request_cy["CY"]["CY-01"]["flag_url"])) + #CY-02 - Lemesos + self.assertEqual(test_request_cy["CY"]["CY-02"]["name"], "Lemesos", + "Expected subdivsion name to be Lemesos, got {}.".format(test_request_cy["CY"]["CY-02"]["name"])) + self.assertEqual(test_request_cy["CY"]["CY-02"]["parent_code"], None, + "Expected subdivision parent code to be None, got {}.".format(test_request_cy["CY"]["CY-02"]["parent_code"])) + self.assertEqual(test_request_cy["CY"]["CY-02"]["type"], "District", + "Expected subdivision type to be District, got {}.".format(test_request_cy["CY"]["CY-02"]["type"])) + self.assertEqual(test_request_cy["CY"]["CY-02"]["latlng"], [34.679, 33.041], + "Expected subdivision latlng to be [34.679, 33.041], got {}.".format(test_request_cy["CY"]["CY-02"]["latlng"])) + self.assertEqual(test_request_cy["CY"]["CY-02"]["flag_url"], None, + "Expected subdivision flag url to be None, got {}.".format(test_request_cy["CY"]["CY-02"]["flag_url"])) +#3.) test_request_lu = requests.get(self.alpha2_base_url + test_alpha2_lu, headers=self.user_agent_header).json() #Luxembourg self.assertIsInstance(test_request_lu, dict, "Expected output object of API to be type dict, got {}.".format(type(test_request_lu))) self.assertEqual(len(test_request_lu), 1, "Expected output object of API to be of length 1, got {}.".format(len(test_request_lu))) self.assertEqual(list(test_request_lu.keys()), ["LU"], "Expected output object of API to contain only the LU key, got {}.".format(list(test_request_lu.keys()))) - - self.assertEqual(test_request_lu["LU"]["area"], 2586, "Expected area to be 2586, got {}.".format(test_request_lu["LU"]["area"])) - self.assertEqual(test_request_lu["LU"]["name"]["common"], "Luxembourg", "") - self.assertEqual(test_request_lu["LU"]["capital"][0], "Luxembourg", "") - self.assertEqual(test_request_lu["LU"]["cca2"], "LU", "") - self.assertEqual(test_request_lu["LU"]["cca3"], "LUX", "") - self.assertEqual(test_request_lu["LU"]["currencies"]["EUR"]['name'], "Euro", "") - self.assertEqual(list(test_request_lu["LU"]["languages"].keys()), ["deu", "fra", "ltz"], "") - self.assertEqual(test_request_lu["LU"]["latlng"], [49.75, 6.167], "") - self.assertEqual(test_request_lu["LU"]["population"], 632275, "") - self.assertEqual(test_request_lu["LU"]["region"], "Europe", "") - self.assertEqual(list(test_request_lu["LU"]["subdivisions"].keys()), - ["LU-CA", "LU-CL", "LU-DI", "LU-EC", "LU-ES", "LU-GR", "LU-LU", "LU-ME", "LU-RD", "LU-RM", "LU-VD", "LU-WI"], "") - for subd in test_request_lu["LU"]["subdivisions"]: - for key in list(test_request_lu["LU"]["subdivisions"][subd].keys()): - self.assertIn(key, self.correct_subdivision_keys, "Key {} not found in list of correct keys:\n{}.".format(key, self.correct_subdivision_keys)) - for col in list(test_request_lu["LU"].keys()): - self.assertIn(col, self.correct_output_cols, "Column {} not found in list of correct columns:\n{}.".format(col, self.correct_output_cols)) -#5.) + self.assertEqual(list(test_request_lu["LU"].keys()), ["LU-CA", "LU-CL", "LU-DI", "LU-EC", "LU-ES", "LU-GR", "LU-LU", "LU-ME", "LU-RD", "LU-RM", "LU-VD", "LU-WI"], + "Expected list of subdivision codes doesn't match output.") + for subd in test_request_lu["LU"]: + self.assertIsNot(test_request_lu["LU"][subd]["name"], None, + "Expected subdivision name to not be None, got {}.".format(test_request_lu["LU"][subd]["name"])) + if not (test_request_lu["LU"][subd]["flag_url"] is None): + self.assertEqual(os.path.splitext(test_request_lu["LU"][subd]["flag_url"])[0], self.flag_base_url + "LU/" + subd, + "Expected flag url to be {}, got {}.".format(self.flag_base_url + "LU/" + subd, os.path.splitext(test_request_lu["LU"][subd]["flag_url"])[0])) + self.assertEqual(requests.get(test_request_lu["LU"][subd]["flag_url"], headers=self.user_agent_header).status_code, 200, + "Flag URL invalid: {}.".format(test_request_lu["LU"][subd]["flag_url"])) + for key in list(test_request_lu["LU"][subd].keys()): + self.assertIn(key, self.correct_subdivision_keys, "Attribute {} not found in list of correct attributes:\n{}.".format(key, self.correct_subdivision_keys)) + + #LU-CA - Capellen + self.assertEqual(test_request_lu["LU"]["LU-CA"]["name"], "Capellen", + "Expected subdivsion name to be Capellen, got {}.".format(test_request_lu["LU"]["LU-CA"]["name"])) + self.assertEqual(test_request_lu["LU"]["LU-CA"]["parent_code"], None, + "Expected subdivision parent code to be None, got {}.".format(test_request_lu["LU"]["LU-CA"]["parent_code"])) + self.assertEqual(test_request_lu["LU"]["LU-CA"]["type"], "Canton", + "Expected subdivision type to be Canton, got {}.".format(test_request_lu["LU"]["LU-CA"]["type"])) + self.assertEqual(test_request_lu["LU"]["LU-CA"]["latlng"], [49.646, 5.991], + "Expected subdivision latlng to be [49.646, 5.991], got {}.".format(test_request_lu["LU"]["LU-CA"]["latlng"])) + self.assertEqual(test_request_lu["LU"]["LU-CA"]["flag_url"], "https://github.com/amckenna41/iso3166-flag-icons/blob/main/iso3166-2-icons/LU/LU-CA.svg", + "Expected subdivision flag url to be https://github.com/amckenna41/iso3166-flag-icons/blob/main/iso3166-2-icons/LU/LU-CA.svg, got {}.".format(test_request_lu["LU"]["LU-CA"]["flag_url"])) + #LU-LU - Luxembourg + self.assertEqual(test_request_lu["LU"]["LU-LU"]["name"], "Luxembourg", + "Expected subdivsion name to be Luxembourg, got {}.".format(test_request_lu["LU"]["LU-LU"]["name"])) + self.assertEqual(test_request_lu["LU"]["LU-LU"]["parent_code"], None, + "Expected subdivision parent code to be None, got {}.".format(test_request_lu["LU"]["LU-LU"]["parent_code"])) + self.assertEqual(test_request_lu["LU"]["LU-LU"]["type"], "Canton", + "Expected subdivision type to be Canton, got {}.".format(test_request_lu["LU"]["LU-LU"]["type"])) + self.assertEqual(test_request_lu["LU"]["LU-LU"]["latlng"], [49.815, 6.13], + "Expected subdivision latlng to be [49.815, 6.13], got {}.".format(test_request_lu["LU"]["LU-LU"]["latlng"])) + self.assertEqual(test_request_lu["LU"]["LU-LU"]["flag_url"], "https://github.com/amckenna41/iso3166-flag-icons/blob/main/iso3166-2-icons/LU/LU-LU.png", + "Expected subdivision flag url to be https://github.com/amckenna41/iso3166-flag-icons/blob/main/iso3166-2-icons/LU/LU-LU.png, got {}.".format(test_request_lu["LU"]["LU-LU"]["flag_url"])) +#4.) test_request_pa_rw = requests.get(self.alpha2_base_url + test_alpha2_pa_rw, headers=self.user_agent_header).json() #Panama and Rwanda self.assertIsInstance(test_request_pa_rw, dict, "Expected output object of API to be type dict, got {}.".format(type(test_request_pa_rw))) self.assertEqual(len(test_request_pa_rw), 2, "Expected output object of API to be of length 2, got {}.".format(len(test_request_pa_rw))) self.assertEqual(list(test_request_pa_rw.keys()), ["PA", "RW"], "Expected output object of API to contain only the PA and RW keys, got {}.".format(list(test_request_pa_rw.keys()))) - - self.assertEqual(test_request_pa_rw["PA"]["area"], 75417, "Expected area to be 75417, got {}.".format(test_request_pa_rw["PA"]["area"])) - self.assertEqual(test_request_pa_rw["PA"]["name"]["common"], "Panama", "") - self.assertEqual(test_request_pa_rw["PA"]["capital"][0], "Panama City", "") - self.assertEqual(test_request_pa_rw["PA"]["cca2"], "PA", "") - self.assertEqual(test_request_pa_rw["PA"]["cca3"], "PAN", "") - self.assertEqual(test_request_pa_rw["PA"]["currencies"]["PAB"]['name'], "Panamanian balboa", "") - self.assertEqual(list(test_request_pa_rw["PA"]["languages"].keys()), ["spa"], "") - self.assertEqual(test_request_pa_rw["PA"]["latlng"], [9, -80], "") - self.assertEqual(test_request_pa_rw["PA"]["population"], 4314768, "") - self.assertEqual(test_request_pa_rw["PA"]["region"], "Americas", "") - self.assertEqual(list(test_request_pa_rw["PA"]["subdivisions"].keys()), - ["PA-1", "PA-10", "PA-2", "PA-3", "PA-4", "PA-5", "PA-6", "PA-7", "PA-8", "PA-9", "PA-EM", "PA-KY", "PA-NB"], "") - for subd in test_request_pa_rw["PA"]["subdivisions"]: - for key in list(test_request_pa_rw["PA"]["subdivisions"][subd].keys()): - self.assertIn(key, self.correct_subdivision_keys, "Key {} not found in list of correct keys:\n{}.".format(key, self.correct_subdivision_keys)) - for col in list(test_request_pa_rw["PA"].keys()): - self.assertIn(col, self.correct_output_cols, "Column {} not found in list of correct columns:\n{}.".format(col, self.correct_output_cols)) - - self.assertEqual(test_request_pa_rw["RW"]["area"], 26338, "Expected area to be 26338, got {}.".format(test_request_pa_rw["RW"]["area"])) - self.assertEqual(test_request_pa_rw["RW"]["name"]["common"], "Rwanda", "") - self.assertEqual(test_request_pa_rw["RW"]["capital"][0], "Kigali", "") - self.assertEqual(test_request_pa_rw["RW"]["cca2"], "RW", "") - self.assertEqual(test_request_pa_rw["RW"]["cca3"], "RWA", "") - self.assertEqual(test_request_pa_rw["RW"]["currencies"]["RWF"]['name'], "Rwandan franc", "") - self.assertEqual(list(test_request_pa_rw["RW"]["languages"].keys()), ["eng", "fra", "kin"], "") - self.assertEqual(test_request_pa_rw["RW"]["latlng"], [-2, 30], "") - self.assertEqual(test_request_pa_rw["RW"]["population"], 12952209, "") - self.assertEqual(test_request_pa_rw["RW"]["region"], "Africa", "") - self.assertEqual(list(test_request_pa_rw["RW"]["subdivisions"].keys()), - ["RW-01", "RW-02", "RW-03", "RW-04", "RW-05"], "") - for subd in test_request_pa_rw["RW"]["subdivisions"]: - for key in list(test_request_pa_rw["RW"]["subdivisions"][subd].keys()): - self.assertIn(key, self.correct_subdivision_keys, "Key {} not found in list of correct keys:\n{}.".format(key, self.correct_subdivision_keys)) - for col in list(test_request_pa_rw["RW"].keys()): - self.assertIn(col, self.correct_output_cols, "Column {} not found in list of correct columns:\n{}.".format(col, self.correct_output_cols)) -#6.) - test_request_mac_mys = requests.get(self.alpha2_base_url + test_alpha2_mac_mys, headers=self.user_agent_header).json() #Macau, Malaysia - - self.assertIsInstance(test_request_mac_mys, dict, "Expected output object of API to be type dict, got {}.".format(type(test_request_mac_mys))) - self.assertEqual(len(test_request_mac_mys), 2, "Expected output object of API to be of length 2, got {}.".format(len(test_request_mac_mys))) - self.assertEqual(list(test_request_mac_mys.keys()), ["MO", "MY"], "Expected output object of API to contain only the MO and MY keys, got {}.".format(list(test_request_mac_mys.keys()))) - - self.assertEqual(test_request_mac_mys["MO"]["area"], 30, "Expected area to be 30, got {}.".format(test_request_mac_mys["MO"]["area"])) - self.assertEqual(test_request_mac_mys["MO"]["name"]["common"], "Macau", "") - self.assertEqual(test_request_mac_mys["MO"]["cca2"], "MO", "") - self.assertEqual(test_request_mac_mys["MO"]["cca3"], "MAC", "") - self.assertEqual(test_request_mac_mys["MO"]["currencies"]["MOP"]['name'], "Macanese pataca", "") - self.assertEqual(list(test_request_mac_mys["MO"]["languages"].keys()), ["por", "zho"], "") - self.assertEqual(test_request_mac_mys["MO"]["latlng"], [22.167, 113.55], "") - self.assertEqual(test_request_mac_mys["MO"]["population"], 649342, "") - self.assertEqual(test_request_mac_mys["MO"]["region"], "Asia", "") - self.assertEqual(test_request_mac_mys["MO"]["subdivisions"], {}, "") - for col in list(test_request_mac_mys["MO"].keys()): - self.assertIn(col, self.correct_output_cols, "Column {} not found in list of correct columns:\n{}.".format(col, self.correct_output_cols)) - - self.assertEqual(test_request_mac_mys["MY"]["area"], 330803, "Expected area to be 330803, got {}.".format(test_request_mac_mys["MY"]["area"])) - self.assertEqual(test_request_mac_mys["MY"]["name"]["common"], "Malaysia", "") - self.assertEqual(test_request_mac_mys["MY"]["capital"][0], "Kuala Lumpur", "") - self.assertEqual(test_request_mac_mys["MY"]["cca2"], "MY", "") - self.assertEqual(test_request_mac_mys["MY"]["cca3"], "MYS", "") - self.assertEqual(test_request_mac_mys["MY"]["currencies"]["MYR"]['name'], "Malaysian ringgit", "") - self.assertEqual(list(test_request_mac_mys["MY"]["languages"].keys()), ["eng", "msa"] , "") - self.assertEqual(test_request_mac_mys["MY"]["latlng"], [2.5, 112.5], "") - self.assertEqual(test_request_mac_mys["MY"]["population"], 32365998, "") - self.assertEqual(test_request_mac_mys["MY"]["region"], "Asia", "") - self.assertEqual(list(test_request_mac_mys["MY"]["subdivisions"].keys()), - ["MY-01", "MY-02", "MY-03", "MY-04", "MY-05", "MY-06", "MY-07", "MY-08", "MY-09", \ - "MY-10", "MY-11", "MY-12", "MY-13", "MY-14", "MY-15", "MY-16"], "") - for subd in test_request_mac_mys["MY"]["subdivisions"]: - for key in list(test_request_mac_mys["MY"]["subdivisions"][subd].keys()): - self.assertIn(key, self.correct_subdivision_keys, "Key {} not found in list of correct keys:\n{}.".format(key, self.correct_subdivision_keys)) - for col in list(test_request_mac_mys["MY"].keys()): - self.assertIn(col, self.correct_output_cols, "Column {} not found in list of correct columns:\n{}.".format(col, self.correct_output_cols)) -#7.) + self.assertEqual(list(test_request_pa_rw["PA"].keys()), ["PA-1", "PA-10", "PA-2", "PA-3", "PA-4", "PA-5", "PA-6", "PA-7", "PA-8", "PA-9", "PA-EM", "PA-KY", "PA-NB"], + "Expected list of subdivision codes doesn't match output.") + self.assertEqual(list(test_request_pa_rw["RW"].keys()), ["RW-01", "RW-02", "RW-03", "RW-04", "RW-05"], "Expected list of subdivision codes doesn't match output.") + for subd in test_request_pa_rw["PA"]: + self.assertIsNot(test_request_pa_rw["PA"][subd]["name"], None, + "Expected subdivision name to not be None, got {}.".format(test_request_pa_rw["PA"][subd]["name"])) + if not (test_request_pa_rw["PA"][subd]["flag_url"] is None): + self.assertEqual(os.path.splitext(test_request_pa_rw["PA"][subd]["flag_url"])[0], self.flag_base_url + "PA/" + subd, + "Expected flag url to be {}, got {}.".format(self.flag_base_url + "PA/" + subd, os.path.splitext(test_request_pa_rw["PA"][subd]["flag_url"])[0])) + self.assertEqual(requests.get(test_request_pa_rw["PA"][subd]["flag_url"], headers=self.user_agent_header).status_code, 200, + "Flag URL invalid: {}.".format(test_request_pa_rw["PA"][subd]["flag_url"])) + for key in list(test_request_pa_rw["PA"][subd].keys()): + self.assertIn(key, self.correct_subdivision_keys, "Attribute {} not found in list of correct attributes:\n{}.".format(key, self.correct_subdivision_keys)) + for subd in test_request_pa_rw["RW"]: + self.assertIsNot(test_request_pa_rw["RW"][subd]["name"], None, + "Expected subdivision name to not be None, got {}.".format(test_request_pa_rw["RW"][subd]["name"])) + if not (test_request_pa_rw["RW"][subd]["flag_url"] is None): + self.assertEqual(os.path.splitext(test_request_pa_rw["RW"][subd]["flag_url"])[0], self.flag_base_url + "RW/" + subd, + "Expected flag url to be {}, got {}.".format(self.flag_base_url + "RW/" + subd, os.path.splitext(test_request_pa_rw["RW"][subd]["flag_url"])[0])) + self.assertEqual(requests.get(test_request_pa_rw["RW"][subd]["flag_url"], headers=self.user_agent_header).status_code, 200, + "Flag URL invalid: {}.".format(test_request_pa_rw["RW"][subd]["flag_url"])) + for key in list(test_request_pa_rw["RW"][subd].keys()): + self.assertIn(key, self.correct_subdivision_keys, "Attribute {} not found in list of correct attributes:\n{}.".format(key, self.correct_subdivision_keys)) + + #PA-4 - Chiriquí + self.assertEqual(test_request_pa_rw["PA"]["PA-4"]["name"], "Chiriquí", + "Expected subdivsion name to be Chiriquí, got {}.".format(test_request_pa_rw["PA"]["PA-4"]["name"])) + self.assertEqual(test_request_pa_rw["PA"]["PA-4"]["parent_code"], None, + "Expected subdivision parent code to be None, got {}.".format(test_request_pa_rw["PA"]["PA-4"]["parent_code"])) + self.assertEqual(test_request_pa_rw["PA"]["PA-4"]["type"], "Province", + "Expected subdivision type to be Province, got {}.".format(test_request_pa_rw["PA"]["PA-4"]["type"])) + self.assertEqual(test_request_pa_rw["PA"]["PA-4"]["latlng"], [8.387, -82.28], + "Expected subdivision latlng to be [8.387, -82.28], got {}.".format(test_request_pa_rw["PA"]["PA-4"]["latlng"])) + self.assertEqual(test_request_pa_rw["PA"]["PA-4"]["flag_url"], "https://github.com/amckenna41/iso3166-flag-icons/blob/main/iso3166-2-icons/PA/PA-4.svg", + "Expected subdivision flag url to be https://github.com/amckenna41/iso3166-flag-icons/blob/main/iso3166-2-icons/PA/PA-4.svg, got {}.".format(test_request_pa_rw["PA"]["PA-4"]["flag_url"])) + #RW-03 - Northern + self.assertEqual(test_request_pa_rw["RW"]["RW-03"]["name"], "Northern", + "Expected subdivsion name to be Northern, got {}.".format(test_request_pa_rw["RW"]["RW-03"]["name"])) + self.assertEqual(test_request_pa_rw["RW"]["RW-03"]["parent_code"], None, + "Expected subdivision parent code to be None, got {}.".format(test_request_pa_rw["RW"]["RW-03"]["parent_code"])) + self.assertEqual(test_request_pa_rw["RW"]["RW-03"]["type"], "Province", + "Expected subdivision type to be Province, got {}.".format(test_request_pa_rw["RW"]["RW-03"]["type"])) + self.assertEqual(test_request_pa_rw["RW"]["RW-03"]["latlng"], [-1.656, 29.882], + "Expected subdivision latlng to be [-1.656, 29.882], got {}.".format(test_request_pa_rw["RW"]["RW-03"]["latlng"])) + self.assertEqual(test_request_pa_rw["RW"]["RW-03"]["flag_url"], None, + "Expected subdivision flag url to be None, got {}.".format(test_request_pa_rw["RW"]["RW-03"]["flag_url"])) +#5.) test_request_error1 = requests.get(self.alpha2_base_url + test_alpha2_error_1, headers=self.user_agent_header).json() #ABCDE self.assertIsInstance(test_request_error1, dict, "Expected output object of API to be type dict, got {}.".format(type(test_request_error1))) @@ -245,7 +253,7 @@ def test_alpha2_endpoint(self): "Error path does not match expected:\n{}.".format(test_request_error1["path"])) self.assertEqual(test_request_error1["status"], 400, "Error status does not match expected:\n{}.".format(test_request_error1["status"])) -#8.) +#6.) test_request_error2 = requests.get(self.alpha2_base_url + test_alpha2_error_2, headers=self.user_agent_header).json() #12345 self.assertIsInstance(test_request_error2, dict, "Expected output object of API to be type dict, got {}.".format(type(test_request_error2))) @@ -277,132 +285,90 @@ def test_name(self): "Türkiye": "Turkey", "Taiwan, Province of China": "Taiwan", "Tanzania, United Republic of": "Tanzania", "United States of America": "United States", "Holy See": "Vatican City", "Venezuela, Bolivarian Republic of": "Venezuela", "Virgin Islands, British": "British Virgin Islands", "Virgin Islands, U.S.": "United States Virgin Islands", "Viet Nam": "Vietnam"} -#1.) - #for each country name, test API returns correct object, test using common.name attribute - for alpha2 in sorted(list(iso3166.countries_by_alpha2.keys())): - country_name = iso3166.countries_by_alpha2[alpha2].name - test_request_name = requests.get(self.name_base_url + country_name, headers=self.user_agent_header).json() - #convert country name to its more common name - if (country_name in list(name_exceptions_converted.keys())): - country_name = name_exceptions_converted[country_name] - self.assertEqual(test_request_name[alpha2]["name"]["common"], country_name, - "Input country name {} and one in output object do not match: {}.".format(country_name, test_request_name[alpha2]["name"]["common"])) -#2.) +#1.) test_request_bj = requests.get(self.name_base_url + test_name_bj, headers=self.user_agent_header).json() #Benin self.assertIsInstance(test_request_bj, dict, "Expected output object of API to be type dict, got {}.".format(type(test_request_bj))) self.assertEqual(len(test_request_bj), 1, "Expected output object of API to be of length 1, got {}.".format(len(test_request_bj))) self.assertEqual(list(test_request_bj.keys()), ["BJ"], "Expected output object of API to contain only the BJ key, got {}.".format(list(test_request_bj.keys()))) - - self.assertEqual(test_request_bj["BJ"]["area"], 112622, "") - self.assertEqual(test_request_bj["BJ"]["name"]["common"], "Benin", "") - self.assertEqual(test_request_bj["BJ"]["capital"][0], "Porto-Novo", "") - self.assertEqual(test_request_bj["BJ"]["cca2"], "BJ", "") - self.assertEqual(test_request_bj["BJ"]["cca3"], "BEN", "") - self.assertEqual(test_request_bj["BJ"]["currencies"]["XOF"]['name'], "West African CFA franc", "") - self.assertEqual(list(test_request_bj["BJ"]["languages"].keys())[0], "fra", "") - self.assertEqual(test_request_bj["BJ"]["latlng"], [9.5, 2.25], "") - self.assertEqual(test_request_bj["BJ"]["population"], 12123198, "") - self.assertEqual(test_request_bj["BJ"]["region"], "Africa", "") - self.assertEqual(list(test_request_bj["BJ"]["subdivisions"].keys()), - ["BJ-AK", "BJ-AL", "BJ-AQ", "BJ-BO", "BJ-CO", "BJ-DO", "BJ-KO", "BJ-LI", "BJ-MO", "BJ-OU", "BJ-PL", "BJ-ZO"], "") - for subd in test_request_bj["BJ"]["subdivisions"]: - for key in list(test_request_bj["BJ"]["subdivisions"][subd].keys()): - self.assertIn(key, self.correct_subdivision_keys, "Key {} not found in list of correct keys:\n{}".format(key, self.correct_subdivision_keys)) - for col in list(test_request_bj["BJ"].keys()): - self.assertIn(col, self.correct_output_cols, "") -#3.) + self.assertEqual(list(test_request_bj["BJ"].keys()), ["BJ-AK", "BJ-AL", "BJ-AQ", "BJ-BO", "BJ-CO", "BJ-DO", "BJ-KO", "BJ-LI", "BJ-MO", "BJ-OU", "BJ-PL", "BJ-ZO"], "") + for subd in test_request_bj["BJ"]: + self.assertIsNot(test_request_bj["BJ"][subd]["name"], None, + "Expected subdivision name to not be None, got {}.".format(test_request_bj["BJ"][subd]["name"])) + if not (test_request_bj["BJ"][subd]["flag_url"] is None): + self.assertEqual(os.path.splitext(test_request_bj["BJ"][subd]["flag_url"])[0], self.flag_base_url + "BJ/" + subd, + "Expected flag url to be {}, got {}.".format(self.flag_base_url + "BJ/" + subd, os.path.splitext(test_request_bj["BJ"][subd]["flag_url"])[0])) + self.assertEqual(requests.get(test_request_bj["BJ"][subd]["flag_url"], headers=self.user_agent_header).status_code, 200, + "Flag URL invalid: {}.".format(test_request_bj["BJ"][subd]["flag_url"])) + for key in list(test_request_bj["BJ"][subd].keys()): + self.assertIn(key, self.correct_subdivision_keys, "Attribute {} not found in list of correct attributes:\n{}.".format(key, self.correct_subdivision_keys)) +#2.) test_request_tj = requests.get(self.name_base_url + test_name_tj, headers=self.user_agent_header).json() #Tajikistan self.assertIsInstance(test_request_tj, dict, "Expected output object of API to be type dict, got {}.".format(type(test_request_tj))) self.assertEqual(len(test_request_tj), 1, "Expected output object of API to be of length 1, got {}.".format(len(test_request_tj))) self.assertEqual(list(test_request_tj.keys()), ["TJ"], "Expected output object of API to contain only the TJ key, got {}.".format(list(test_request_tj.keys()))) - - self.assertEqual(test_request_tj["TJ"]["area"], 143100, "") - self.assertEqual(test_request_tj["TJ"]["name"]["common"], "Tajikistan", "") - self.assertEqual(test_request_tj["TJ"]["capital"][0], "Dushanbe", "") - self.assertEqual(test_request_tj["TJ"]["cca2"], "TJ", "") - self.assertEqual(test_request_tj["TJ"]["cca3"], "TJK", "") - self.assertEqual(test_request_tj["TJ"]["currencies"]["TJS"]['name'], "Tajikistani somoni", "") - self.assertEqual(list(test_request_tj["TJ"]["languages"].keys())[0], "rus", "") - self.assertEqual(test_request_tj["TJ"]["latlng"], [39, 71], "") - self.assertEqual(test_request_tj["TJ"]["population"], 9537642, "") - self.assertEqual(test_request_tj["TJ"]["region"], "Asia", "") - self.assertEqual(list(test_request_tj["TJ"]["subdivisions"].keys()), - ["TJ-DU", "TJ-GB", "TJ-KT", "TJ-RA", "TJ-SU"], "") - for subd in test_request_tj["TJ"]["subdivisions"]: - for key in list(test_request_tj["TJ"]["subdivisions"][subd].keys()): - self.assertIn(key, self.correct_subdivision_keys, "Key {} not found in list of correct keys:\n{}".format(key, self.correct_subdivision_keys)) - for col in list(test_request_tj["TJ"].keys()): - self.assertIn(col, self.correct_output_cols, "") -#4.) + self.assertEqual(list(test_request_tj["TJ"].keys()), ["TJ-DU", "TJ-GB", "TJ-KT", "TJ-RA", "TJ-SU"], "") + for subd in test_request_tj["TJ"]: + self.assertIsNot(test_request_tj["TJ"][subd]["name"], None, + "Expected subdivision name to not be None, got {}.".format(test_request_tj["TJ"][subd]["name"])) + if not (test_request_tj["TJ"][subd]["flag_url"] is None): + self.assertEqual(os.path.splitext(test_request_tj["TJ"][subd]["flag_url"])[0], self.flag_base_url + "TJ/" + subd, + "Expected flag url to be {}, got {}.".format(self.flag_base_url + "TJ/" + subd, os.path.splitext(test_request_tj["TJ"][subd]["flag_url"])[0])) + self.assertEqual(requests.get(test_request_tj["TJ"][subd]["flag_url"], headers=self.user_agent_header).status_code, 200, + "Flag URL invalid: {}.".format(test_request_tj["TJ"][subd]["flag_url"])) + for key in list(test_request_tj["TJ"][subd].keys()): + self.assertIn(key, self.correct_subdivision_keys, "Attribute {} not found in list of correct attributes:\n{}.".format(key, self.correct_subdivision_keys)) +#3.) test_request_sd = requests.get(self.name_base_url + test_name_sd, headers=self.user_agent_header).json() #Sudan self.assertIsInstance(test_request_sd, dict, "Expected output object of API to be type dict, got {}.".format(type(test_request_sd))) self.assertEqual(len(test_request_sd), 1, "Expected output object of API to be of length 1, got {}.".format(len(test_request_sd))) self.assertEqual(list(test_request_sd.keys()), ["SD"], "Expected output object of API to contain only the SD key, got {}.".format(list(test_request_sd.keys()))) - - self.assertEqual(test_request_sd["SD"]["area"], 1886068, "") - self.assertEqual(test_request_sd["SD"]["name"]["common"], "Sudan", "") - self.assertEqual(test_request_sd["SD"]["capital"][0], "Khartoum", "") - self.assertEqual(test_request_sd["SD"]["cca2"], "SD", "") - self.assertEqual(test_request_sd["SD"]["cca3"], "SDN", "") - self.assertEqual(test_request_sd["SD"]["currencies"]["SDG"]['name'], "Sudanese pound", "") - self.assertEqual(list(test_request_sd["SD"]["languages"].keys())[0], "ara", "") - self.assertEqual(test_request_sd["SD"]["latlng"], [15, 30], "") - self.assertEqual(test_request_sd["SD"]["population"], 43849269, "") - self.assertEqual(test_request_sd["SD"]["region"], "Africa", "") - self.assertEqual(list(test_request_sd["SD"]["subdivisions"].keys()), + self.assertEqual(list(test_request_sd["SD"].keys()), ["SD-DC", "SD-DE", "SD-DN", "SD-DS", "SD-DW", "SD-GD", "SD-GK", "SD-GZ", "SD-KA", "SD-KH", \ "SD-KN", "SD-KS", "SD-NB", "SD-NO", "SD-NR", "SD-NW", "SD-RS", "SD-SI"], "") - for subd in test_request_sd["SD"]["subdivisions"]: - for key in list(test_request_sd["SD"]["subdivisions"][subd].keys()): - self.assertIn(key, self.correct_subdivision_keys, "Key {} not found in list of correct keys:\n{}".format(key, self.correct_subdivision_keys)) - for col in list(test_request_tj["TJ"].keys()): - self.assertIn(col, self.correct_output_cols, "") -#5.) + for subd in test_request_sd["SD"]: + self.assertIsNot(test_request_sd["SD"][subd]["name"], None, + "Expected subdivision name to not be None, got {}.".format(test_request_sd["SD"][subd]["name"])) + if not (test_request_sd["SD"][subd]["flag_url"] is None): + self.assertEqual(os.path.splitext(test_request_sd["SD"][subd]["flag_url"])[0], self.flag_base_url + "SD/" + subd, + "Expected flag url to be {}, got {}.".format(self.flag_base_url + "SD/" + subd, os.path.splitext(test_request_sd["SD"][subd]["flag_url"])[0])) + self.assertEqual(requests.get(test_request_sd["SD"][subd]["flag_url"], headers=self.user_agent_header).status_code, 200, + "Flag URL invalid: {}.".format(test_request_sd["SD"][subd]["flag_url"])) + for key in list(test_request_sd["SD"][subd].keys()): + self.assertIn(key, self.correct_subdivision_keys, "Attribute {} not found in list of correct attributes:\n{}.".format(key, self.correct_subdivision_keys)) +#4.) test_request_ml_ni = requests.get(self.name_base_url + test_name_ml_ni, headers=self.user_agent_header).json() #Mali and Nicaragua self.assertIsInstance(test_request_ml_ni, dict, "Expected output object of API to be type dict, got {}.".format(type(test_request_ml_ni))) self.assertEqual(len(test_request_ml_ni), 2, "Expected output object of API to be of length 2, got {}.".format(len(test_request_ml_ni))) self.assertEqual(list(test_request_ml_ni.keys()), ["ML", "NI"], "Expected output object of API to contain only the ML and NI keys, got {}.".format(list(test_request_ml_ni.keys()))) - - self.assertEqual(test_request_ml_ni["ML"]["area"], 1240192, "") - self.assertEqual(test_request_ml_ni["ML"]["name"]["common"], "Mali", "") - self.assertEqual(test_request_ml_ni["ML"]["capital"][0], "Bamako", "") - self.assertEqual(test_request_ml_ni["ML"]["cca2"], "ML", "") - self.assertEqual(test_request_ml_ni["ML"]["cca3"], "MLI", "") - self.assertEqual(test_request_ml_ni["ML"]["currencies"]["XOF"]['name'], "West African CFA franc", "") - self.assertEqual(list(test_request_ml_ni["ML"]["languages"].keys())[0], "fra", "") - self.assertEqual(test_request_ml_ni["ML"]["latlng"], [17, -4], "") - self.assertEqual(test_request_ml_ni["ML"]["population"], 20250834, "") - self.assertEqual(test_request_ml_ni["ML"]["region"], "Africa", "") - self.assertEqual(list(test_request_ml_ni["ML"]["subdivisions"].keys()), - ["ML-1", "ML-10", "ML-2", "ML-3", "ML-4", "ML-5", "ML-6", "ML-7", "ML-8", "ML-9", "ML-BKO"], "") - for subd in test_request_ml_ni["ML"]["subdivisions"]: - for key in list(test_request_ml_ni["ML"]["subdivisions"][subd].keys()): - self.assertIn(key, self.correct_subdivision_keys, "Key {} not found in list of correct keys:\n{}".format(key, self.correct_subdivision_keys)) - for col in list(test_request_ml_ni["ML"].keys()): - self.assertIn(col, self.correct_output_cols, "") - - self.assertEqual(test_request_ml_ni["NI"]["area"], 130373, "") - self.assertEqual(test_request_ml_ni["NI"]["name"]["common"], "Nicaragua", "") - self.assertEqual(test_request_ml_ni["NI"]["capital"][0], "Managua", "") - self.assertEqual(test_request_ml_ni["NI"]["cca2"], "NI", "") - self.assertEqual(test_request_ml_ni["NI"]["cca3"], "NIC", "") - self.assertEqual(test_request_ml_ni["NI"]["currencies"]["NIO"]['name'], "Nicaraguan córdoba", "") - self.assertEqual(list(test_request_ml_ni["NI"]["languages"].keys())[0], "spa", "") - self.assertEqual(test_request_ml_ni["NI"]["latlng"], [13, -85], "") - self.assertEqual(test_request_ml_ni["NI"]["population"], 6624554, "") - self.assertEqual(test_request_ml_ni["NI"]["region"], "Americas", "") - self.assertEqual(list(test_request_ml_ni["NI"]["subdivisions"].keys()), + self.assertEqual(list(test_request_ml_ni["ML"].keys()), ["ML-1", "ML-10", "ML-2", "ML-3", "ML-4", "ML-5", "ML-6", "ML-7", "ML-8", "ML-9", "ML-BKO"], "") + for subd in test_request_ml_ni["ML"]: + self.assertIsNot(test_request_ml_ni["ML"][subd]["name"], None, + "Expected subdivision name to not be None, got {}.".format(test_request_ml_ni["ML"][subd]["name"])) + if not (test_request_ml_ni["ML"][subd]["flag_url"] is None): + self.assertEqual(os.path.splitext(test_request_ml_ni["ML"][subd]["flag_url"])[0], self.flag_base_url + "ML/" + subd, + "Expected flag url to be {}, got {}.".format(self.flag_base_url + "ML/" + subd, os.path.splitext(test_request_ml_ni["ML"][subd]["flag_url"])[0])) + self.assertEqual(requests.get(test_request_ml_ni["ML"][subd]["flag_url"], headers=self.user_agent_header).status_code, 200, + "Flag URL invalid: {}.".format(test_request_ml_ni["ML"][subd]["flag_url"])) + for key in list(test_request_ml_ni["ML"][subd].keys()): + self.assertIn(key, self.correct_subdivision_keys, "Attribute {} not found in list of correct attributes:\n{}.".format(key, self.correct_subdivision_keys)) + + self.assertEqual(list(test_request_ml_ni["NI"].keys()), ["NI-AN", "NI-AS", "NI-BO", "NI-CA", "NI-CI", "NI-CO", "NI-ES", "NI-GR", "NI-JI", "NI-LE", "NI-MD", "NI-MN", "NI-MS", "NI-MT", "NI-NS", "NI-RI", "NI-SJ"], "") - for subd in test_request_ml_ni["NI"]["subdivisions"]: - for key in list(test_request_ml_ni["NI"]["subdivisions"][subd].keys()): - self.assertIn(key, self.correct_subdivision_keys, "Key {} not found in list of correct keys:\n{}".format(key, self.correct_subdivision_keys)) - for col in list(test_request_ml_ni["NI"].keys()): - self.assertIn(col, self.correct_output_cols, "") -#6.) + for subd in test_request_ml_ni["NI"]: + self.assertIsNot(test_request_ml_ni["NI"][subd]["name"], None, + "Expected subdivision name to not be None, got {}.".format(test_request_ml_ni["NI"][subd]["name"])) + if not (test_request_ml_ni["NI"][subd]["flag_url"] is None): + self.assertEqual(os.path.splitext(test_request_ml_ni["NI"][subd]["flag_url"])[0], self.flag_base_url + "NI/" + subd, + "Expected flag url to be {}, got {}.".format(self.flag_base_url + "NI/" + subd, os.path.splitext(test_request_ml_ni["NI"][subd]["flag_url"])[0])) + self.assertEqual(requests.get(test_request_ml_ni["NI"][subd]["flag_url"], headers=self.user_agent_header).status_code, 200, + "Flag URL invalid: {}.".format(test_request_ml_ni["NI"][subd]["flag_url"])) + for key in list(test_request_ml_ni["NI"][subd].keys()): + self.assertIn(key, self.correct_subdivision_keys, "Attribute {} not found in list of correct attributes:\n{}.".format(key, self.correct_subdivision_keys)) +#5.) test_request_error = requests.get(self.name_base_url + test_name_error1, headers=self.user_agent_header).json() #ABCDEF self.assertIsInstance(test_request_error, dict, "Expected output object of API to be type dict, got {}.".format(type(test_request_error))) @@ -413,7 +379,7 @@ def test_name(self): "Error path does not match expected:\n{}".format(test_request_error["path"])) self.assertEqual(test_request_error["status"], 400, "Error status does not match expected:\n{}".format(test_request_error["status"])) -#7.) +#6.) test_request_error = requests.get(self.name_base_url + test_name_error2, headers=self.user_agent_header).json() #12345 self.assertIsInstance(test_request_error, dict, "Expected output object of API to be type dict, got {}.".format(type(test_request_error))) @@ -425,102 +391,7 @@ def test_name(self): self.assertEqual(test_request_error["status"], 400, "Error status does not match expected:\n{}".format(test_request_error["status"])) - def test_filter_output(self): - """ Testing filter_output function that filters out attributes from output object. """ - test_attribute_capital = "capital" - test_attribute_population = "population" - test_attribute_region = "region" - test_attribute_cca2_cca3_landlocked = "cca2, cca3, landlocked" - test_attribute_languages_subregion_timezones = "languages, subregion, timezones" - test_attribute_error1 = "invalidAttribute" - test_attribute_error2 = "12345" -#1.) - test_request_attribute_capital = requests.get(self.alpha2_base_url + "DK" + "?filter=" + test_attribute_capital, headers=self.user_agent_header).json() #Denmark - - self.assertIsInstance(test_request_attribute_capital, dict, "Expected output object of API to be type dict, got {}.".format(type(test_request_attribute_capital))) - self.assertEqual(len(test_request_attribute_capital), 1, "Expected output object of API to be of length 1, got {}.".format(len(test_request_attribute_capital))) - self.assertEqual(list(test_request_attribute_capital.keys()), ["DK"], "Expected output object of API to contain only the DK key, got {}.".format(list(test_request_attribute_capital.keys()))) - self.assertEqual(list(test_request_attribute_capital["DK"].keys()), ["capital"], "Expected only capital city attribute to be in output object, got {}\n.".format(list(test_request_attribute_capital["DK"].keys()))) - self.assertEqual(test_request_attribute_capital["DK"]["capital"][0], "Copenhagen", "Expected capital city attribute value to be Copenhagen, got {}\n.".format(test_request_attribute_capital["DK"]['capital'])) -#2.) - test_request_attribute_population = requests.get(self.alpha2_base_url + "GH" + "?filter=" + test_attribute_population, headers=self.user_agent_header).json() #Ghana - - self.assertIsInstance(test_request_attribute_population, dict, "Expected output object of API to be type dict, got {}.".format(type(test_request_attribute_population))) - self.assertEqual(len(test_request_attribute_population), 1, "Expected output object of API to be of length 1, got {}.".format(len(test_request_attribute_population))) - self.assertEqual(list(test_request_attribute_population.keys()), ["GH"], "Expected output object of API to contain only the GH key, got {}.".format(list(test_request_attribute_population.keys()))) - self.assertEqual(list(test_request_attribute_population["GH"].keys()), ["population"], "Expected only population attribute to be in output object, got {}\n.".format(list(test_request_attribute_population["GH"].keys()))) - self.assertEqual(test_request_attribute_population["GH"]["population"], 31072945, "Expected population attribute value to be 31072945, got {}\n.".format(test_request_attribute_population["GH"]['population'])) -#3.) - test_request_attribute_region = requests.get(self.alpha2_base_url + "IM,MQ" + "?filter=" + test_attribute_region, headers=self.user_agent_header).json() #Isle of Man, Martinique - - self.assertIsInstance(test_request_attribute_region, dict, "Expected output object of API to be type dict, got {}.".format(type(test_request_attribute_region))) - self.assertEqual(len(test_request_attribute_region), 2, "Expected output object of API to be of length 2, got {}.".format(len(test_request_attribute_region))) - self.assertEqual(list(test_request_attribute_region.keys()), ["IM", "MQ"], "Expected output object of API to contain only the IM and MQ keys, got {}.".format(list(test_request_attribute_region.keys()))) - self.assertEqual(list(test_request_attribute_region["IM"].keys()), ["region"], "Expected only region attribute to be in output object, got {}\n.".format(list(test_request_attribute_region["IM"].keys()))) - self.assertEqual(list(test_request_attribute_region["MQ"].keys()), ["region"], "Expected only region attribute to be in output object, got {}\n.".format(list(test_request_attribute_region["MQ"].keys()))) - self.assertEqual(test_request_attribute_region["IM"]["region"], "Europe", "Expected region attribute value to be Europe, got {}\n.".format(test_request_attribute_region["IM"]['region'])) - self.assertEqual(test_request_attribute_region["MQ"]["region"], "Americas", "Expected region attribute value to be Americas, got {}\n.".format(test_request_attribute_region["MQ"]['region'])) -#4.) - test_request_attribute_cca2_cca3_landlocked = requests.get(self.alpha2_base_url + "NU,PK,PL" + "?filter=" + test_attribute_cca2_cca3_landlocked, headers=self.user_agent_header).json() #Niue, Pakistan, Poland - - self.assertIsInstance(test_request_attribute_cca2_cca3_landlocked, dict, "Expected output object of API to be type dict, got {}.".format(type(test_request_attribute_cca2_cca3_landlocked))) - self.assertEqual(len(test_request_attribute_cca2_cca3_landlocked), 3, "Expected output object of API to be of length 3, got {}.".format(len(test_request_attribute_cca2_cca3_landlocked))) - self.assertEqual(list(test_request_attribute_cca2_cca3_landlocked.keys()), ["NU", "PK", "PL"], "Expected output object of API to contain only the NU, PL and PK keys, got {}.".format(list(test_request_attribute_cca2_cca3_landlocked.keys()))) - self.assertEqual(list(test_request_attribute_cca2_cca3_landlocked["NU"].keys()), ["cca2", "cca3", "landlocked"], "Expected only cca2, cca3 and landlocked attributes to be in output object, got {}\n.".format(list(test_request_attribute_cca2_cca3_landlocked["NU"].keys()))) - self.assertEqual(list(test_request_attribute_cca2_cca3_landlocked["PL"].keys()), ["cca2", "cca3", "landlocked"], "Expected only cca2, cca3 and landlocked attributes to be in output object, got {}\n.".format(list(test_request_attribute_cca2_cca3_landlocked["NU"].keys()))) - self.assertEqual(list(test_request_attribute_cca2_cca3_landlocked["PK"].keys()), ["cca2", "cca3", "landlocked"], "Expected only cca2, cca3 and landlocked attributes to be in output object, got {}\n.".format(list(test_request_attribute_cca2_cca3_landlocked["NU"].keys()))) - self.assertEqual(test_request_attribute_cca2_cca3_landlocked["NU"]["cca2"], "NU", "Expected cca2 attribute value to be NU, got {}\n.".format(test_request_attribute_cca2_cca3_landlocked["NU"]['cca2'])) - self.assertEqual(test_request_attribute_cca2_cca3_landlocked["PL"]["cca2"], "PL", "Expected cca2 attribute value to be PL, got {}\n.".format(test_request_attribute_cca2_cca3_landlocked["PL"]['cca2'])) - self.assertEqual(test_request_attribute_cca2_cca3_landlocked["PK"]["cca2"], "PK", "Expected cca2 attribute value to be PK, got {}\n.".format(test_request_attribute_cca2_cca3_landlocked["PK"]['cca2'])) - self.assertEqual(test_request_attribute_cca2_cca3_landlocked["NU"]["cca3"], "NIU", "Expected cca3 attribute value to be NIU, got {}\n.".format(test_request_attribute_cca2_cca3_landlocked["NU"]['cca3'])) - self.assertEqual(test_request_attribute_cca2_cca3_landlocked["PL"]["cca3"], "POL", "Expected cca3 attribute value to be POL, got {}\n.".format(test_request_attribute_cca2_cca3_landlocked["PL"]['cca3'])) - self.assertEqual(test_request_attribute_cca2_cca3_landlocked["PK"]["cca3"], "PAK", "Expected cca3 attribute value to be PAK, got {}\n.".format(test_request_attribute_cca2_cca3_landlocked["PK"]['cca3'])) - self.assertEqual(test_request_attribute_cca2_cca3_landlocked["NU"]["landlocked"], False, "Expected landlocked attribute value to be False, got {}\n.".format(test_request_attribute_cca2_cca3_landlocked["NU"]['landlocked'])) - self.assertEqual(test_request_attribute_cca2_cca3_landlocked["PL"]["landlocked"], False, "Expected landlocked attribute value to be False, got {}\n.".format(test_request_attribute_cca2_cca3_landlocked["PL"]['landlocked'])) - self.assertEqual(test_request_attribute_cca2_cca3_landlocked["PK"]["landlocked"], False, "Expected landlocked attribute value to be False, got {}\n.".format(test_request_attribute_cca2_cca3_landlocked["PK"]['landlocked'])) -#5.) - test_request_attribute_languages_subregion_timezones = requests.get(self.alpha2_base_url + "SA,SH,SR,SS" + "?filter=" + test_attribute_languages_subregion_timezones, headers=self.user_agent_header).json() #Saudi Arabia, Saint Helena, Suriname, South Sudan - - self.assertIsInstance(test_request_attribute_languages_subregion_timezones, dict, "Expected output object of API to be type dict, got {}.".format(type(test_request_attribute_languages_subregion_timezones))) - self.assertEqual(len(test_request_attribute_languages_subregion_timezones), 4, "Expected output object of API to be of length 4, got {}.".format(len(test_request_attribute_languages_subregion_timezones))) - self.assertEqual(list(test_request_attribute_languages_subregion_timezones.keys()), ["SA", "SH", "SR", "SS"], "Expected output object of API to contain only the SA, SH, SR and SS keys, got {}.".format(list(test_request_attribute_languages_subregion_timezones.keys()))) - self.assertEqual(list(test_request_attribute_languages_subregion_timezones["SA"].keys()), ["languages", "subregion", "timezones"], "Expected only languages, subregion and timezones attributes to be in output object, got {}\n.".format(list(test_request_attribute_languages_subregion_timezones["SA"].keys()))) - self.assertEqual(list(test_request_attribute_languages_subregion_timezones["SH"].keys()), ["languages", "subregion", "timezones"], "Expected only languages, subregion and timezones attributes to be in output object, got {}\n.".format(list(test_request_attribute_languages_subregion_timezones["SH"].keys()))) - self.assertEqual(list(test_request_attribute_languages_subregion_timezones["SR"].keys()), ["languages", "subregion", "timezones"], "Expected only languages, subregion and timezones attributes to be in output object, got {}\n.".format(list(test_request_attribute_languages_subregion_timezones["SR"].keys()))) - self.assertEqual(list(test_request_attribute_languages_subregion_timezones["SS"].keys()), ["languages", "subregion", "timezones"], "Expected only languages, subregion and timezones attributes to be in output object, got {}\n.".format(list(test_request_attribute_languages_subregion_timezones["SS"].keys()))) - - self.assertEqual(list(test_request_attribute_languages_subregion_timezones["SA"]["languages"].values())[0], "Arabic", "Expected language attribute value to be Arabic, got {}\n.".format(test_request_attribute_languages_subregion_timezones["SA"]['languages'])) - self.assertEqual(list(test_request_attribute_languages_subregion_timezones["SH"]["languages"].values())[0], "English", "Expected language attribute value to be English, got {}\n.".format(test_request_attribute_languages_subregion_timezones["SH"]['languages'])) - self.assertEqual(list(test_request_attribute_languages_subregion_timezones["SR"]["languages"].values())[0], "Dutch", "Expected language attribute value to be Dutch, got {}\n.".format(test_request_attribute_languages_subregion_timezones["SR"]['languages'])) - self.assertEqual(list(test_request_attribute_languages_subregion_timezones["SS"]["languages"].values())[0], "English", "Expected language attribute value to be English, got {}\n.".format(test_request_attribute_languages_subregion_timezones["SS"]['languages'])) - self.assertEqual(test_request_attribute_languages_subregion_timezones["SA"]["subregion"], "Western Asia", "Expected subregion attribute value to be Western Asia, got {}\n.".format(test_request_attribute_languages_subregion_timezones["SA"]['subregion'])) - self.assertEqual(test_request_attribute_languages_subregion_timezones["SH"]["subregion"], "Western Africa", "Expected subregion attribute value to be Western Africa, got {}\n.".format(test_request_attribute_languages_subregion_timezones["SH"]['subregion'])) - self.assertEqual(test_request_attribute_languages_subregion_timezones["SR"]["subregion"], "South America", "Expected subregion attribute value to be South America, got {}\n.".format(test_request_attribute_languages_subregion_timezones["SR"]['subregion'])) - self.assertEqual(test_request_attribute_languages_subregion_timezones["SS"]["subregion"], "Middle Africa", "Expected subregion attribute value to be English, got {}\n.".format(test_request_attribute_languages_subregion_timezones["SS"]['subregion'])) - self.assertEqual(test_request_attribute_languages_subregion_timezones["SA"]["timezones"][0], "UTC+03:00", "Expected timezones attribute value to be UTC+03:00, got {}\n.".format(test_request_attribute_languages_subregion_timezones["SA"]['timezones'][0])) - self.assertEqual(test_request_attribute_languages_subregion_timezones["SH"]["timezones"][0], "UTC+00:00", "Expected timezones attribute value to be UTC+00:00, got {}\n.".format(test_request_attribute_languages_subregion_timezones["SH"]['timezones'][0])) - self.assertEqual(test_request_attribute_languages_subregion_timezones["SR"]["timezones"][0], "UTC-03:00", "Expected timezones attribute value to be UTC-03:00, got {}\n.".format(test_request_attribute_languages_subregion_timezones["SR"]['timezones'][0])) - self.assertEqual(test_request_attribute_languages_subregion_timezones["SS"]["timezones"][0], "UTC+03:00", "Expected timezones attribute value to be UTC+03:00, got {}\n.".format(test_request_attribute_languages_subregion_timezones["SS"]['timezones'][0])) -#6.) - test_request_attribute_error1 = requests.get(self.alpha2_base_url + "TN" + "?filter=" + test_attribute_error1, headers=self.user_agent_header).json() #Tunisia - - self.assertIsInstance(test_request_attribute_error1, dict, "Expected output object of API to be type dict, got {}.".format(type(test_request_attribute_error1))) - self.assertEqual(len(test_request_attribute_error1), 1, "Expected output object of API to be of length 1, got {}.".format(len(test_request_attribute_error1))) - self.assertEqual(list(test_request_attribute_error1.keys()), ["TN"], "Expected output object of API to contain only the TN key, got {}.".format(list(test_request_attribute_error1.keys()))) - for col in list(test_request_attribute_error1["TN"].keys()): - self.assertIn(col, self.correct_output_cols, "Column {} not found in list of correct columns:\n{}.".format(col, self.correct_output_cols)) -#7.) - test_request_attribute_error2 = requests.get(self.alpha2_base_url + "TV,UG" + "?filter=" + test_attribute_error2, headers=self.user_agent_header).json() #Tuvalu, Uganda - - self.assertIsInstance(test_request_attribute_error2, dict, "Expected output object of API to be type dict, got {}.".format(type(test_request_attribute_error2))) - self.assertEqual(len(test_request_attribute_error2), 2, "Expected output object of API to be of length 2, got {}.".format(len(test_request_attribute_error2))) - self.assertEqual(list(test_request_attribute_error2.keys()), ["TV", "UG"], "Expected output object of API to contain only the TV and UG keys, got {}.".format(list(test_request_attribute_error2.keys()))) - for col in list(test_request_attribute_error2["TV"].keys()): - self.assertIn(col, self.correct_output_cols, "Column {} not found in list of correct columns:\n{}.".format(col, self.correct_output_cols)) - for col in list(test_request_attribute_error2["UG"].keys()): - self.assertIn(col, self.correct_output_cols, "Column {} not found in list of correct columns:\n{}.".format(col, self.correct_output_cols)) - - @unittest.skip("Skipping /all endpoint tests to overload server.") + @unittest.skip("Skipping /all endpoint tests to not overload server.") def test_all(self): """ Test 'all' endpoint which returns all data for all ISO 3166 countries. """ #1.)