diff --git a/HISTORY.rst b/HISTORY.rst index 99fd48b..1d3d91d 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -21,6 +21,13 @@ History ``aiohttp.encode_basic_auth()`` instead of the ``aiohttp.BasicAuth`` / ``auth=`` parameter, which are deprecated as of aiohttp 3.14.0. As a result, the minimum required ``aiohttp`` version is now 3.14.0. +* The ``ip_address.anonymizer`` object may now contain a ``residential`` + attribute. This is a ``geoip2.records.AnonymizerFeed`` object sourced from + the GeoIP Residential Proxy database and contains the following fields: + ``confidence``, ``network_last_seen``, and ``provider_name``. Because the + residential proxy feed is a superset of what is in the Anonymous Plus + database, ``anonymizer`` may now contain only this attribute. This requires + ``geoip2`` 5.3.0 or greater. 3.2.0 (2025-11-20) ++++++++++++++++++ diff --git a/tests/data/factors-response.json b/tests/data/factors-response.json index 1aee01f..9317084 100644 --- a/tests/data/factors-response.json +++ b/tests/data/factors-response.json @@ -28,7 +28,12 @@ "is_residential_proxy": true, "is_tor_exit_node": true, "network_last_seen": "2025-01-15", - "provider_name": "TestVPN" + "provider_name": "TestVPN", + "residential": { + "confidence": 82, + "network_last_seen": "2026-05-11", + "provider_name": "quickshift" + } }, "city": { "confidence": 42, diff --git a/tests/data/insights-response.json b/tests/data/insights-response.json index 14a4152..bcee439 100644 --- a/tests/data/insights-response.json +++ b/tests/data/insights-response.json @@ -28,7 +28,12 @@ "is_residential_proxy": true, "is_tor_exit_node": true, "network_last_seen": "2025-01-15", - "provider_name": "TestVPN" + "provider_name": "TestVPN", + "residential": { + "confidence": 82, + "network_last_seen": "2026-05-11", + "provider_name": "quickshift" + } }, "city": { "confidence": 42, diff --git a/tests/test_models.py b/tests/test_models.py index b7fa6c8..a0079c2 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -197,6 +197,11 @@ def test_ip_address(self) -> None: "is_tor_exit_node": True, "network_last_seen": "2025-01-15", "provider_name": "TestVPN", + "residential": { + "confidence": 82, + "network_last_seen": "2026-05-11", + "provider_name": "quickshift", + }, }, traits={ "is_anonymous": True, @@ -238,6 +243,14 @@ def test_ip_address(self) -> None: ) self.assertEqual("TestVPN", address.anonymizer.provider_name) + # Test anonymizer.residential attribute + self.assertEqual(82, address.anonymizer.residential.confidence) + self.assertEqual( + datetime.date(2026, 5, 11), + address.anonymizer.residential.network_last_seen, + ) + self.assertEqual("quickshift", address.anonymizer.residential.provider_name) + self.assertEqual("ANONYMOUS_IP", address.risk_reasons[0].code) self.assertEqual( "The IP address belongs to an anonymous network. " diff --git a/tests/test_webservice.py b/tests/test_webservice.py index 2dfff37..d949642 100644 --- a/tests/test_webservice.py +++ b/tests/test_webservice.py @@ -236,6 +236,14 @@ def test_200(self) -> None: self.assertEqual("310", model.ip_address.traits.mobile_country_code) self.assertEqual("004", model.ip_address.traits.mobile_network_code) self.assertEqual("ANONYMOUS_IP", model.ip_address.risk_reasons[0].code) + self.assertEqual( + 82, + model.ip_address.anonymizer.residential.confidence, + ) + self.assertEqual( + "quickshift", + model.ip_address.anonymizer.residential.provider_name, + ) def test_authorization_header(self) -> None: # Credentials must be sent via the Authorization header rather than the