diff --git a/HISTORY.rst b/HISTORY.rst index 1038039a..0b95de3b 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -15,6 +15,7 @@ History * Python 3.3 and 3.4 are no longer supported. * Updated documentation of anonymizer attributes - ``is_anonymous_vpn`` and ``is_hosting_provider`` - to be more descriptive. +* Added support for ``user_count`` trait for the GeoIP2 Precision webservice. 2.9.0 (2018-05-25) ++++++++++++++++++ diff --git a/geoip2/records.py b/geoip2/records.py index a31fa6dc..2ba26ebf 100644 --- a/geoip2/records.py +++ b/geoip2/records.py @@ -688,6 +688,15 @@ class Traits(Record): :type: unicode + .. attribute:: user_count + + The estimated number of users sharing the IP/network during the past 24 + hours. For IPv4, the count is for the individual IP. For IPv6, the count + is for the /64 network. This attribute is only available from GeoIP2 + Precision Insights. + + :type: int + .. attribute:: user_type The user type associated with the IP @@ -733,6 +742,7 @@ def __init__(self, network=None, organization=None, prefix_len=None, + user_count=None, user_type=None, **_): self.autonomous_system_number = autonomous_system_number @@ -750,6 +760,7 @@ def __init__(self, self.isp = isp self.organization = organization self.user_type = user_type + self.user_count = user_count self.ip_address = ip_address self._network = network self._prefix_len = prefix_len diff --git a/tests/models_test.py b/tests/models_test.py index f542e07d..fa2d8c5b 100644 --- a/tests/models_test.py +++ b/tests/models_test.py @@ -104,6 +104,7 @@ def test_insights_full(self): 'isp': 'Comcast', 'network_speed': 'cable/DSL', 'organization': 'Blorg', + 'user_count': 2, 'user_type': 'college', }, } @@ -183,6 +184,8 @@ def test_insights_full(self): self.assertIs(model.traits.is_satellite_provider, True) self.assertIs(model.traits.is_tor_exit_node, True) + self.assertEqual(model.traits.user_count, 2) + def test_insights_min(self): model = geoip2.models.Insights({'traits': {'ip_address': '5.6.7.8'}}) self.assertEqual(type(model), geoip2.models.Insights, diff --git a/tests/webservice_test.py b/tests/webservice_test.py index e6ccdb30..b8d50709 100644 --- a/tests/webservice_test.py +++ b/tests/webservice_test.py @@ -4,6 +4,7 @@ import sys sys.path.append('..') +import copy import geoip2 import requests_mock from geoip2.errors import (AddressNotFoundError, AuthenticationError, @@ -59,6 +60,11 @@ def setUp(self): }, } + # this is not a comprehensive representation of the + # JSON from the server + insights = copy.deepcopy(country) + insights['traits']['user_count'] = 2 + def _content_type(self, endpoint): return ('application/vnd.maxmind.com-' + endpoint + '+json; charset=UTF-8; version=1.0') @@ -276,7 +282,7 @@ def test_city_ok(self, mock): @requests_mock.mock() def test_insights_ok(self, mock): mock.get(self.base_uri + 'insights/1.2.3.4', - json=self.country, + json=self.insights, status_code=200, headers={'Content-Type': self._content_type('country')}) insights = self.client.insights('1.2.3.4') @@ -284,6 +290,7 @@ def test_insights_ok(self, mock): 'return value of client.insights') self.assertEqual(insights.traits.network, compat_ip_network('1.2.3.0/24'), 'network') + self.assertEqual(insights.traits.user_count, 2, 'user_count is 2') def test_named_constructor_args(self): id = '47'