From 891d814caf216d4cbbeab39a9d751a27656d751e Mon Sep 17 00:00:00 2001 From: Clinton Blackburn Date: Mon, 1 Dec 2014 18:37:12 -0500 Subject: [PATCH] Replaced iso3166 with django-countries This change ensures the country names in the CSVs match those displayed in Insights. --- analytics_data_api/constants/country.py | 29 +++++++++++++++++++++- analytics_data_api/tests.py | 16 +++++++++++- analytics_data_api/v0/models.py | 7 +----- analytics_data_api/v0/tests/test_models.py | 5 ++-- analytics_data_api/v0/tests/test_views.py | 4 +-- analyticsdataserver/settings/base.py | 1 + requirements/base.txt | 2 +- 7 files changed, 50 insertions(+), 14 deletions(-) diff --git a/analytics_data_api/constants/country.py b/analytics_data_api/constants/country.py index 28439772..fba00c11 100644 --- a/analytics_data_api/constants/country.py +++ b/analytics_data_api/constants/country.py @@ -1,4 +1,31 @@ -from iso3166 import Country +""" +This file holds constants and helper methods related to countries. All codes are assumed to be valid ISO 3166 country +codes. +""" +from collections import namedtuple +from django_countries import countries + +Country = namedtuple('Country', 'name, alpha2, alpha3, numeric') UNKNOWN_COUNTRY_CODE = u'UNKNOWN' UNKNOWN_COUNTRY = Country(UNKNOWN_COUNTRY_CODE, None, None, None) + + +def _get_country_property(code, property_name): + return unicode(getattr(countries, property_name)(code)) + + +def get_country(code): + if not code: + return UNKNOWN_COUNTRY + + name = _get_country_property(code, 'name') + if not name: + return UNKNOWN_COUNTRY + + args = [] + properties = ['alpha2', 'alpha3', 'numeric'] + for property_name in properties: + args.append(_get_country_property(code, property_name)) + + return Country(name, *args) diff --git a/analytics_data_api/tests.py b/analytics_data_api/tests.py index b28b1a6e..7fed1ec2 100644 --- a/analytics_data_api/tests.py +++ b/analytics_data_api/tests.py @@ -1,10 +1,11 @@ from django.contrib.auth.models import User from django.core.management import call_command, CommandError from django.test import TestCase - from django_dynamic_fixture import G from rest_framework.authtoken.models import Token +from analytics_data_api.constants.country import get_country, UNKNOWN_COUNTRY + from analytics_data_api.utils import delete_user_auth_token, set_user_auth_token @@ -77,3 +78,16 @@ def test_set_key_conflict(self): self.assertFalse(Token.objects.filter(user=user2).exists()) call_command('set_api_key', user2.username, key) self.assertFalse(Token.objects.filter(user=user2).exists()) + + +class CountryTests(TestCase): + def test_get_country(self): + # Countries should be accessible 2 or 3 digit country code + self.assertEqual(get_country('US'), get_country('USA')) + + # Use common name for Taiwan + self.assertEqual(get_country('TW').name, 'Taiwan') + + # Return unknown country if code is invalid + self.assertEqual(get_country('A1'), UNKNOWN_COUNTRY) + self.assertEqual(get_country(None), UNKNOWN_COUNTRY) diff --git a/analytics_data_api/v0/models.py b/analytics_data_api/v0/models.py index f9af9cfb..41371bbb 100644 --- a/analytics_data_api/v0/models.py +++ b/analytics_data_api/v0/models.py @@ -1,5 +1,4 @@ from django.db import models -from iso3166 import countries from analytics_data_api.constants import country, genders @@ -120,11 +119,7 @@ def country(self): """ Returns a Country object representing the country in this model's country_code. """ - try: - return countries.get(self.country_code) - except (KeyError, ValueError, AttributeError): - # Country code is not valid ISO-3166 - return country.UNKNOWN_COUNTRY + return country.get_country(self.country_code) class Meta(BaseCourseEnrollment.Meta): db_table = 'course_enrollment_location_current' diff --git a/analytics_data_api/v0/tests/test_models.py b/analytics_data_api/v0/tests/test_models.py index 37b97b51..8806d8c5 100644 --- a/analytics_data_api/v0/tests/test_models.py +++ b/analytics_data_api/v0/tests/test_models.py @@ -1,14 +1,13 @@ from django.test import TestCase from django_dynamic_fixture import G -from iso3166 import countries from analytics_data_api.v0 import models -from analytics_data_api.constants.country import UNKNOWN_COUNTRY +from analytics_data_api.constants.country import UNKNOWN_COUNTRY, get_country class CourseEnrollmentByCountryTests(TestCase): def test_country(self): - country = countries.get('US') + country = get_country('US') self.assertEqual(country.alpha2, 'US') instance = G(models.CourseEnrollmentByCountry, country_code=country.alpha2) self.assertEqual(instance.country, country) diff --git a/analytics_data_api/v0/tests/test_views.py b/analytics_data_api/v0/tests/test_views.py index c7e49094..55c519a8 100644 --- a/analytics_data_api/v0/tests/test_views.py +++ b/analytics_data_api/v0/tests/test_views.py @@ -10,9 +10,9 @@ from django.conf import settings from django_dynamic_fixture import G -from iso3166 import countries import pytz from opaque_keys.edx.keys import CourseKey +from analytics_data_api.constants.country import get_country from analytics_data_api.v0 import models from analytics_data_api.constants import country, enrollment_modes, genders @@ -550,7 +550,7 @@ def generate_data(self, course_id=None): def setUp(self): super(CourseEnrollmentByLocationViewTests, self).setUp() - self.country = countries.get('US') + self.country = get_country('US') self.generate_data() diff --git a/analyticsdataserver/settings/base.py b/analyticsdataserver/settings/base.py index 05b48656..e7ce5831 100644 --- a/analyticsdataserver/settings/base.py +++ b/analyticsdataserver/settings/base.py @@ -184,6 +184,7 @@ 'rest_framework', 'rest_framework.authtoken', 'rest_framework_swagger', + 'django_countries', ) LOCAL_APPS = ( diff --git a/requirements/base.txt b/requirements/base.txt index a5a0feb2..27c74759 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -5,5 +5,5 @@ djangorestframework==2.4.4 # BSD ipython==2.1.0 # BSD django-rest-swagger==0.1.14 # BSD djangorestframework-csv==1.3.3 # BSD -iso3166==0.1 # MIT +django-countries==3.0.1 # MIT -e git+https://github.com/edx/opaque-keys.git@d45d0bd8d64c69531be69178b9505b5d38806ce0#egg=opaque-keys