Skip to content

Commit 927aa5b

Browse files
committed
Add is_anycast to Traits
1 parent 1c8c87a commit 927aa5b

File tree

5 files changed

+44
-2
lines changed

5 files changed

+44
-2
lines changed

HISTORY.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ History
99

1010
* IMPORTANT: Python 3.8 or greater is required. If you are using an older
1111
version, please use an earlier release.
12+
* The ``is_anycast`` attribute was added to ``geoip2.record.Traits``.
13+
This returns ``True`` if the IP address belongs to an
14+
`anycast network <https://en.wikipedia.org/wiki/Anycast>`_.
15+
This is available for the GeoIP2 Country, City Plus, and Insights web services
16+
and the GeoIP2 Country, City, and Enterprise databases.
1217

1318
4.7.0 (2023-05-09)
1419
++++++++++++++++++

geoip2/records.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -634,6 +634,14 @@ class Traits(Record):
634634
635635
:type: str
636636
637+
.. attribute:: is_anycast
638+
639+
This is true if the IP address is anycast.
640+
This attribute is available from the Country, City Plus, Insights
641+
web services and the Country, City, Enterprise databases.
642+
643+
:type: bool
644+
637645
.. attribute:: is_anonymous
638646
639647
This is true if the IP address belongs to any sort of anonymous network.
@@ -815,6 +823,7 @@ class Traits(Record):
815823
autonomous_system_organization: Optional[str]
816824
connection_type: Optional[str]
817825
domain: Optional[str]
826+
is_anycast: bool
818827
is_anonymous: bool
819828
is_anonymous_proxy: bool
820829
is_anonymous_vpn: bool
@@ -841,6 +850,7 @@ def __init__(
841850
autonomous_system_organization: Optional[str] = None,
842851
connection_type: Optional[str] = None,
843852
domain: Optional[str] = None,
853+
is_anycast: bool = False,
844854
is_anonymous: bool = False,
845855
is_anonymous_proxy: bool = False,
846856
is_anonymous_vpn: bool = False,
@@ -866,6 +876,7 @@ def __init__(
866876
self.autonomous_system_organization = autonomous_system_organization
867877
self.connection_type = connection_type
868878
self.domain = domain
879+
self.is_anycast = is_anycast
869880
self.is_anonymous = is_anonymous
870881
self.is_anonymous_proxy = is_anonymous_proxy
871882
self.is_anonymous_vpn = is_anonymous_vpn

tests/database_test.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,10 @@ def test_city(self) -> None:
135135
record.location.accuracy_radius, 100, "The accuracy_radius is populated"
136136
)
137137
self.assertEqual(record.registered_country.is_in_european_union, False)
138+
self.assertFalse(record.traits.is_anycast)
139+
140+
record = reader.city("214.1.1.0")
141+
self.assertTrue(record.traits.is_anycast)
138142

139143
reader.close()
140144

@@ -171,6 +175,11 @@ def test_country(self) -> None:
171175
self.assertEqual(record.traits.network, ipaddress.ip_network("81.2.69.160/27"))
172176
self.assertEqual(record.country.is_in_european_union, False)
173177
self.assertEqual(record.registered_country.is_in_european_union, False)
178+
self.assertFalse(record.traits.is_anycast)
179+
180+
record = reader.country("214.1.1.0")
181+
self.assertTrue(record.traits.is_anycast)
182+
174183
reader.close()
175184

176185
def test_domain(self) -> None:
@@ -211,12 +220,15 @@ def test_enterprise(self) -> None:
211220
self.assertEqual(
212221
record.traits.network, ipaddress.ip_network("74.209.16.0/20")
213222
)
223+
self.assertFalse(record.traits.is_anycast)
214224

215225
record = reader.enterprise("149.101.100.0")
216-
217226
self.assertEqual(record.traits.mobile_country_code, "310")
218227
self.assertEqual(record.traits.mobile_network_code, "004")
219228

229+
record = reader.enterprise("214.1.1.0")
230+
self.assertTrue(record.traits.is_anycast)
231+
220232
def test_isp(self) -> None:
221233
with geoip2.database.Reader(
222234
"tests/data/test-data/GeoIP2-ISP-Test.mmdb"

tests/models_test.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ def test_insights_full(self) -> None:
7575
"connection_type": "Cable/DSL",
7676
"domain": "example.com",
7777
"ip_address": "1.2.3.4",
78+
"is_anycast": True,
7879
"is_anonymous": True,
7980
"is_anonymous_proxy": True,
8081
"is_anonymous_vpn": True,
@@ -191,6 +192,7 @@ def test_insights_full(self) -> None:
191192
self.assertIs(model.registered_country.is_in_european_union, False)
192193
self.assertIs(model.represented_country.is_in_european_union, True)
193194

195+
self.assertIs(model.traits.is_anycast, True)
194196
self.assertIs(model.traits.is_anonymous, True)
195197
self.assertIs(model.traits.is_anonymous_proxy, True)
196198
self.assertIs(model.traits.is_anonymous_vpn, True)
@@ -322,6 +324,11 @@ def test_city_full(self) -> None:
322324
"Canada",
323325
"registered_country name is correct",
324326
)
327+
self.assertEqual(
328+
model.traits.is_anycast,
329+
False,
330+
"traits is_anycast returns False by default",
331+
)
325332
self.assertEqual(
326333
model.traits.is_anonymous_proxy,
327334
False,

tests/webservice_test.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,11 @@ class TestBaseClient(unittest.TestCase):
4444
"iso_code": "DE",
4545
"names": {"en": "Germany"},
4646
},
47-
"traits": {"ip_address": "1.2.3.4", "network": "1.2.3.0/24"},
47+
"traits": {
48+
"ip_address": "1.2.3.4",
49+
"is_anycast": True,
50+
"network": "1.2.3.0/24"
51+
},
4852
}
4953

5054
# this is not a comprehensive representation of the
@@ -104,6 +108,7 @@ def test_country_ok(self):
104108
self.assertEqual(
105109
country.traits.network, ipaddress.ip_network("1.2.3.0/24"), "network"
106110
)
111+
self.assertTrue(country.traits.is_anycast)
107112
self.assertEqual(country.raw, self.country, "raw response is correct")
108113

109114
@httprettified
@@ -328,6 +333,7 @@ def test_city_ok(self):
328333
self.assertEqual(
329334
city.traits.network, ipaddress.ip_network("1.2.3.0/24"), "network"
330335
)
336+
self.assertTrue(city.traits.is_anycast)
331337

332338
@httprettified
333339
def test_insights_ok(self):
@@ -345,6 +351,7 @@ def test_insights_ok(self):
345351
self.assertEqual(
346352
insights.traits.network, ipaddress.ip_network("1.2.3.0/24"), "network"
347353
)
354+
self.assertTrue(insights.traits.is_anycast)
348355
self.assertEqual(insights.traits.static_ip_score, 1.3, "static_ip_score is 1.3")
349356
self.assertEqual(insights.traits.user_count, 2, "user_count is 2")
350357

0 commit comments

Comments
 (0)