Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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)
++++++++++++++++++
Expand Down
11 changes: 11 additions & 0 deletions geoip2/records.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
3 changes: 3 additions & 0 deletions tests/models_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ def test_insights_full(self):
'isp': 'Comcast',
'network_speed': 'cable/DSL',
'organization': 'Blorg',
'user_count': 2,
'user_type': 'college',
},
}
Expand Down Expand Up @@ -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,
Expand Down
9 changes: 8 additions & 1 deletion tests/webservice_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import sys
sys.path.append('..')

import copy
import geoip2
import requests_mock
from geoip2.errors import (AddressNotFoundError, AuthenticationError,
Expand Down Expand Up @@ -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')
Expand Down Expand Up @@ -276,14 +282,15 @@ 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')
self.assertEqual(type(insights), geoip2.models.Insights,
'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'
Expand Down