Repository: saleor/saleor

Issue:
Geoip conflicting with Python 3.5?
It appears that python-geoip won't work with the current setup (utilizing Python 3.5).
I get this stack trace:

```
Environment:

Request Method: GET
Request URL: http://127.0.0.1:8000/

Django Version: 1.9.1
Python Version: 3.5.1
Installed Applications:
['offsite_storage',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.sitemaps',
 'django.contrib.sites',
 'django.contrib.staticfiles',
 'django.contrib.admin',
 'django.contrib.auth',
 'saleor.userprofile',
 'saleor.product',
 'saleor.cart',
 'saleor.checkout',
 'saleor.core',
 'saleor.order',
 'saleor.registration',
 'saleor.dashboard',
 'saleor.shipping',
 'versatileimagefield',
 'babeldjango',
 'bootstrap3',
 'django_prices',
 'emailit',
 'mptt',
 'payments',
 'selectable',
 'materializecssform',
 'rest_framework']
Installed Middleware:
['django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.locale.LocaleMiddleware',
 'babeldjango.middleware.LocaleMiddleware',
 'saleor.cart.middleware.CartMiddleware',
 'saleor.core.middleware.DiscountMiddleware',
 'saleor.core.middleware.GoogleAnalytics',
 'saleor.core.middleware.CountryMiddleware',
 'saleor.core.middleware.CurrencyMiddleware']



Traceback:

File "/home/eightbit/saleor/env/lib/python3.5/site-packages/django/core/handlers/base.py" in get_response
  123.                 response = middleware_method(request)

File "/home/eightbit/saleor/saleor/saleor/core/middleware.py" in process_request
  37.             request.country = get_country_by_ip(request.META['REMOTE_ADDR'])

File "/home/eightbit/saleor/saleor/saleor/core/__init__.py" in get_country_by_ip
  14.     geo_data = geolite2.lookup(ip_address)

File "/home/eightbit/saleor/env/lib/python3.5/site-packages/geoip.py" in lookup
  364.         return self._get_actual_db().lookup(ip_addr)

File "/home/eightbit/saleor/env/lib/python3.5/site-packages/geoip.py" in _get_actual_db
  350.             rv = self._load_database()

File "/home/eightbit/saleor/env/lib/python3.5/site-packages/geoip.py" in _load_database
  342.         return mod.loader(self, sys.modules[__name__])

File "/home/eightbit/saleor/env/lib/python3.5/site-packages/_geoip_geolite2/__init__.py" in loader
  9.     return mod.open_database(filename)

File "/home/eightbit/saleor/env/lib/python3.5/site-packages/geoip.py" in open_database
  508.     md = _read_mmdb_metadata(buf)

File "/home/eightbit/saleor/env/lib/python3.5/site-packages/geoip.py" in _read_mmdb_metadata
  382.                        buf.size() - MMDB_METADATA_BLOCK_MAX_SIZE)

Exception Type: TypeError at /
Exception Value: a bytes-like object is required, not 'str'
```

python-geoip seems to be abandoned from looking at its GitHub page. Perhaps it should be replaced with something else?



Discussion:
I merged that commit and had the same problem, also (with Python 3.5).

@mociepka I would recommend [maxminddb-geolite2](https://github.com/rr2do2/maxminddb-geolite2) which supports Python 3.

I like `python-geoip` because it has separate package for data updates. I try fix it.
Ref. https://github.com/mitsuhiko/python-geoip/issues/2


Resolving patch:
diff --git a/saleor/core/__init__.py b/saleor/core/__init__.py
--- a/saleor/core/__init__.py
+++ b/saleor/core/__init__.py
@@ -4,16 +4,20 @@
 from django.conf import settings
 from django_countries import countries
 from django_countries.fields import Country
-from geoip import geolite2
+from geolite2 import geolite2
 
 TOKEN_PATTERN = ('(?P<token>[0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}'
                  '-[0-9a-z]{12})')
 
 
 def get_country_by_ip(ip_address):
-    geo_data = geolite2.lookup(ip_address)
-    if geo_data and geo_data.country in countries:
-        return Country(geo_data.country)
+    reader = geolite2.reader()
+    geo_data = reader.get(ip_address)
+    geolite2.close()
+    if geo_data and 'country' in geo_data and 'iso_code' in geo_data['country']:
+        country_iso_code = geo_data['country']['iso_code']
+        if country_iso_code in countries:
+            return Country(country_iso_code)
 
 
 def get_currency_for_country(country):


Test patch:
diff --git a/saleor/core/test_core.py b/saleor/core/test_core.py
--- a/saleor/core/test_core.py
+++ b/saleor/core/test_core.py
@@ -4,14 +4,19 @@
 from . import get_country_by_ip, get_currency_for_country, Country
 
 
-@pytest.mark.parametrize('lookup, country', [
-    (Mock(return_value=Mock(country='PL')), Country('PL')),
-    (Mock(return_value=Mock(country='UNKNOWN')), None),
+@pytest.mark.parametrize('reader, expected_country', [
+    (Mock(return_value=Mock(get=Mock(return_value={
+        'country': {'iso_code': 'PL'}}))), Country('PL')),
+    (Mock(return_value=Mock(get=Mock(return_value={
+        'country': {'iso_code': 'UNKNOWN'}}))), None),
+    (Mock(return_value=Mock(get=Mock(return_value=None))), None),
+    (Mock(return_value=Mock(get=Mock(return_value={}))), None),
+    (Mock(return_value=Mock(get=Mock(return_value={'country': {}}))), None),
 ])
-def test_get_country_by_ip(lookup, country, monkeypatch):
-    monkeypatch.setattr('saleor.core.geolite2.lookup', lookup)
+def test_get_country_by_ip(reader, expected_country, monkeypatch):
+    monkeypatch.setattr('saleor.core.geolite2.reader', reader)
     country = get_country_by_ip('127.0.0.1')
-    assert  country == country
+    assert country == expected_country
 
 
 @pytest.mark.parametrize('settings, country, expected_currency', [