Skip to content

Commit ed175f6

Browse files
authoredNov 18, 2021
Merge pull request #121 from maxmind/greg/mcc-mnc
Add MCC/MNC support
2 parents ee9dd7b + 7b15d13 commit ed175f6

File tree

9 files changed

+122
-55
lines changed

9 files changed

+122
-55
lines changed
 

‎.github/workflows/lint.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
- name: Set up Python
2020
uses: actions/setup-python@v2
2121
with:
22-
python-version: 3.9
22+
python-version: "3.10"
2323

2424
- name: Install dependencies
2525
run: |

‎.github/workflows/test.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
# We don't test on Windows currently as it appears mocket may not
1515
# work there.
1616
platform: [ubuntu-latest, macos-latest]
17-
python-version: [3.6, 3.7, 3.8, 3.9]
17+
python-version: [3.6, 3.7, 3.8, 3.9, "3.10"]
1818

1919
name: Python ${{ matrix.python-version }} on ${{ matrix.platform }}
2020
runs-on: ${{ matrix.platform }}

‎HISTORY.rst

+12
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,20 @@
1+
12
.. :changelog:
23
34
History
45
-------
56

7+
4.5.0
8+
++++++++++++++++++
9+
10+
* Support for mobile country code (MCC) and mobile network codes (MNC) was
11+
added for the GeoIP2 ISP and Enterprise databases as well as the GeoIP2
12+
City and Insights web services. ``mobile_country_code`` and
13+
``mobile_network_code`` attributes were added to ``geoip2.model.ISP``
14+
for the GeoIP2 ISP database and ``geoip2.record.Traits`` for the
15+
Enterprise database and the GeoIP2 City and Insights web services.
16+
We expect this data to be available by late January, 2022.
17+
618
4.4.0 (2021-09-24)
719
++++++++++++++++++
820

‎geoip2/models.py

+31-11
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@ class AnonymousIP(SimpleModel):
404404
405405
The IP address used in the lookup.
406406
407-
:type: unicode
407+
:type: str
408408
409409
.. attribute:: network
410410
@@ -448,13 +448,13 @@ class ASN(SimpleModel):
448448
The organization associated with the registered autonomous system number
449449
for the IP address.
450450
451-
:type: unicode
451+
:type: str
452452
453453
.. attribute:: ip_address
454454
455455
The IP address used in the lookup.
456456
457-
:type: unicode
457+
:type: str
458458
459459
.. attribute:: network
460460
@@ -495,13 +495,13 @@ class ConnectionType(SimpleModel):
495495
496496
Additional values may be added in the future.
497497
498-
:type: unicode
498+
:type: str
499499
500500
.. attribute:: ip_address
501501
502502
The IP address used in the lookup.
503503
504-
:type: unicode
504+
:type: str
505505
506506
.. attribute:: network
507507
@@ -528,13 +528,13 @@ class Domain(SimpleModel):
528528
529529
The domain associated with the IP address.
530530
531-
:type: unicode
531+
:type: str
532532
533533
.. attribute:: ip_address
534534
535535
The IP address used in the lookup.
536536
537-
:type: unicode
537+
:type: str
538538
539539
.. attribute:: network
540540
@@ -569,25 +569,41 @@ class ISP(ASN):
569569
The organization associated with the registered autonomous system number
570570
for the IP address.
571571
572-
:type: unicode
572+
:type: str
573573
574574
.. attribute:: isp
575575
576576
The name of the ISP associated with the IP address.
577577
578-
:type: unicode
578+
:type: str
579+
580+
.. attribute: mobile_country_code
581+
582+
The `mobile country code (MCC)
583+
<https://en.wikipedia.org/wiki/Mobile_country_code>`_ associated with the
584+
IP address and ISP.
585+
586+
:type: str
587+
588+
.. attribute: mobile_network_code
589+
590+
The `mobile network code (MNC)
591+
<https://en.wikipedia.org/wiki/Mobile_country_code>`_ associated with the
592+
IP address and ISP.
593+
594+
:type: str
579595
580596
.. attribute:: organization
581597
582598
The name of the organization associated with the IP address.
583599
584-
:type: unicode
600+
:type: str
585601
586602
.. attribute:: ip_address
587603
588604
The IP address used in the lookup.
589605
590-
:type: unicode
606+
:type: str
591607
592608
.. attribute:: network
593609
@@ -599,10 +615,14 @@ class ISP(ASN):
599615
"""
600616

601617
isp: Optional[str]
618+
mobile_country_code: Optional[str]
619+
mobile_network_code: Optional[str]
602620
organization: Optional[str]
603621

604622
# pylint:disable=too-many-arguments
605623
def __init__(self, raw: Dict[str, Union[str, int]]) -> None:
606624
super().__init__(raw)
607625
self.isp = cast(Optional[str], raw.get("isp"))
626+
self.mobile_country_code = cast(Optional[str], raw.get("mobile_country_code"))
627+
self.mobile_network_code = cast(Optional[str], raw.get("mobile_network_code"))
608628
self.organization = cast(Optional[str], raw.get("organization"))

‎geoip2/records.py

+44-20
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ class City(PlaceRecord):
7676
The name of the city based on the locales list passed to the
7777
constructor.
7878
79-
:type: unicode
79+
:type: str
8080
8181
.. attribute:: names
8282
@@ -117,7 +117,7 @@ class Continent(PlaceRecord):
117117
A two character continent code like "NA" (North America)
118118
or "OC" (Oceania).
119119
120-
:type: unicode
120+
:type: str
121121
122122
.. attribute:: geoname_id
123123
@@ -130,7 +130,7 @@ class Continent(PlaceRecord):
130130
Returns the name of the continent based on the locales list passed to
131131
the constructor.
132132
133-
:type: unicode
133+
:type: str
134134
135135
.. attribute:: names
136136
@@ -191,14 +191,14 @@ class Country(PlaceRecord):
191191
<http://en.wikipedia.org/wiki/ISO_3166-1>`_ alpha code for the
192192
country.
193193
194-
:type: unicode
194+
:type: str
195195
196196
.. attribute:: name
197197
198198
The name of the country based on the locales list passed to the
199199
constructor.
200200
201-
:type: unicode
201+
:type: str
202202
203203
.. attribute:: names
204204
@@ -266,14 +266,14 @@ class RepresentedCountry(Country):
266266
The two-character `ISO 3166-1
267267
<http://en.wikipedia.org/wiki/ISO_3166-1>`_ alpha code for the country.
268268
269-
:type: unicode
269+
:type: str
270270
271271
.. attribute:: name
272272
273273
The name of the country based on the locales list passed to the
274274
constructor.
275275
276-
:type: unicode
276+
:type: str
277277
278278
.. attribute:: names
279279
@@ -289,7 +289,7 @@ class RepresentedCountry(Country):
289289
country. Currently we only return ``military`` but this could expand to
290290
include other types in the future.
291291
292-
:type: unicode
292+
:type: str
293293
294294
"""
295295

@@ -376,7 +376,7 @@ class Location(Record):
376376
Zone Database <http://www.iana.org/time-zones>`_, e.g.,
377377
"America/New_York".
378378
379-
:type: unicode
379+
:type: str
380380
381381
"""
382382

@@ -443,7 +443,7 @@ class Postal(Record):
443443
codes are not available for all countries. In some countries, this will
444444
only contain part of the postal code.
445445
446-
:type: unicode
446+
:type: str
447447
448448
.. attribute:: confidence
449449
@@ -496,14 +496,14 @@ class Subdivision(PlaceRecord):
496496
contain the subdivision portion of the `ISO 3166-2 code
497497
<http://en.wikipedia.org/wiki/ISO_3166-2>`_.
498498
499-
:type: unicode
499+
:type: str
500500
501501
.. attribute:: name
502502
503503
The name of the subdivision based on the locales list passed to the
504504
constructor.
505505
506-
:type: unicode
506+
:type: str
507507
508508
.. attribute:: names
509509
@@ -598,7 +598,7 @@ class Traits(Record):
598598
the IP address. This attribute is only available from the City and
599599
Insights web service end points and the GeoIP2 Enterprise database.
600600
601-
:type: unicode
601+
:type: str
602602
603603
.. attribute:: connection_type
604604
@@ -613,7 +613,7 @@ class Traits(Record):
613613
614614
This attribute is only available in the GeoIP2 Enterprise database.
615615
616-
:type: unicode
616+
:type: str
617617
618618
.. attribute:: domain
619619
@@ -623,7 +623,7 @@ class Traits(Record):
623623
from the City and Insights web service end points and the GeoIP2
624624
Enterprise database.
625625
626-
:type: unicode
626+
:type: str
627627
628628
.. attribute:: ip_address
629629
@@ -633,7 +633,7 @@ class Traits(Record):
633633
running on. If the system is behind a NAT, this may differ from the IP
634634
address locally assigned to it.
635635
636-
:type: unicode
636+
:type: str
637637
638638
.. attribute:: is_anonymous
639639
@@ -713,7 +713,7 @@ class Traits(Record):
713713
714714
.. attribute:: is_tor_exit_node
715715
716-
This is true if the IP address is a Tor exit node. This attribute is
716+
This is true if the IP address is a Tor exit node. This attribute is
717717
only available from GeoIP2 Precision Insights.
718718
719719
:type: bool
@@ -724,7 +724,25 @@ class Traits(Record):
724724
only available from the City and Insights web service end points and the
725725
GeoIP2 Enterprise database.
726726
727-
:type: unicode
727+
:type: str
728+
729+
.. attribute: mobile_country_code
730+
731+
The `mobile country code (MCC)
732+
<https://en.wikipedia.org/wiki/Mobile_country_code>`_ associated with the
733+
IP address and ISP. This attribute is available from the City and
734+
Insights web services and the GeoIP2 Enterprise database.
735+
736+
:type: str
737+
738+
.. attribute: mobile_network_code
739+
740+
The `mobile network code (MNC)
741+
<https://en.wikipedia.org/wiki/Mobile_country_code>`_ associated with the
742+
IP address and ISP. This attribute is available from the City and
743+
Insights web services and the GeoIP2 Enterprise database.
744+
745+
:type: str
728746
729747
.. attribute:: network
730748
@@ -740,7 +758,7 @@ class Traits(Record):
740758
attribute is only available from the City and Insights web service end
741759
points and the GeoIP2 Enterprise database.
742760
743-
:type: unicode
761+
:type: str
744762
745763
.. attribute:: static_ip_score
746764
@@ -789,7 +807,7 @@ class Traits(Record):
789807
This attribute is only available from the Insights end point and the
790808
GeoIP2 Enterprise database.
791809
792-
:type: unicode
810+
:type: str
793811
794812
"""
795813

@@ -808,6 +826,8 @@ class Traits(Record):
808826
is_tor_exit_node: bool
809827
isp: Optional[str]
810828
ip_address: Optional[str]
829+
mobile_country_code: Optional[str]
830+
mobile_network_code: Optional[str]
811831
organization: Optional[str]
812832
static_ip_score: Optional[float]
813833
user_count: Optional[int]
@@ -838,6 +858,8 @@ def __init__(
838858
static_ip_score: Optional[float] = None,
839859
user_count: Optional[int] = None,
840860
user_type: Optional[str] = None,
861+
mobile_country_code: Optional[str] = None,
862+
mobile_network_code: Optional[str] = None,
841863
**_,
842864
) -> None:
843865
self.autonomous_system_number = autonomous_system_number
@@ -854,6 +876,8 @@ def __init__(
854876
self.is_satellite_provider = is_satellite_provider
855877
self.is_tor_exit_node = is_tor_exit_node
856878
self.isp = isp
879+
self.mobile_country_code = mobile_country_code
880+
self.mobile_network_code = mobile_network_code
857881
self.organization = organization
858882
self.static_ip_score = static_ip_score
859883
self.user_type = user_type

‎setup.cfg

+3-2
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,15 @@ universal = 1
1212
disable = duplicate-code
1313

1414
[tox:tox]
15-
envlist = py36, py37, py38, py39, mypy
15+
envlist = py36, py37, py38, py39, py310, mypy
1616

1717
[gh-actions]
1818
python =
1919
3.6: py36
2020
3.7: py37
2121
3.8: py38
22-
3.9: py39, mypy
22+
3.9: py39
23+
"3.10": py310, mypy
2324

2425
[testenv]
2526
deps =

‎setup.py

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
"Programming Language :: Python :: 3.7",
4141
"Programming Language :: Python :: 3.8",
4242
"Programming Language :: Python :: 3.9",
43+
"Programming Language :: Python :: 3.10",
4344
"Programming Language :: Python",
4445
"Topic :: Internet :: Proxy Servers",
4546
"Topic :: Internet",

‎tests/data

Submodule data updated 46 files

‎tests/database_test.py

+28-19
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ def test_city(self) -> None:
117117
self.assertEqual(
118118
record.country.name, "United Kingdom", "The default locale is en"
119119
)
120-
self.assertEqual(record.country.is_in_european_union, True)
120+
self.assertEqual(record.country.is_in_european_union, False)
121121
self.assertEqual(
122122
record.location.accuracy_radius, 100, "The accuracy_radius is populated"
123123
)
@@ -156,7 +156,7 @@ def test_country(self) -> None:
156156
record.traits.ip_address, "81.2.69.160", "IP address is added to model"
157157
)
158158
self.assertEqual(record.traits.network, ipaddress.ip_network("81.2.69.160/27"))
159-
self.assertEqual(record.country.is_in_european_union, True)
159+
self.assertEqual(record.country.is_in_european_union, False)
160160
self.assertEqual(record.registered_country.is_in_european_union, False)
161161
reader.close()
162162

@@ -199,27 +199,36 @@ def test_enterprise(self) -> None:
199199
record.traits.network, ipaddress.ip_network("74.209.16.0/20")
200200
)
201201

202-
def test_isp(self) -> None:
203-
reader = geoip2.database.Reader("tests/data/test-data/GeoIP2-ISP-Test.mmdb")
202+
record = reader.enterprise("149.101.100.0")
204203

205-
ip_address = "1.128.0.0"
206-
record = reader.isp(ip_address)
207-
self.assertEqual(record, eval(repr(record)), "ISP repr can be eval'd")
204+
self.assertEqual(record.traits.mobile_country_code, "310")
205+
self.assertEqual(record.traits.mobile_network_code, "004")
208206

209-
self.assertEqual(record.autonomous_system_number, 1221)
210-
self.assertEqual(record.autonomous_system_organization, "Telstra Pty Ltd")
211-
self.assertEqual(record.isp, "Telstra Internet")
212-
self.assertEqual(record.organization, "Telstra Internet")
213-
self.assertEqual(record.ip_address, ip_address)
214-
self.assertEqual(record.network, ipaddress.ip_network("1.128.0.0/11"))
207+
def test_isp(self) -> None:
208+
with geoip2.database.Reader(
209+
"tests/data/test-data/GeoIP2-ISP-Test.mmdb"
210+
) as reader:
211+
ip_address = "1.128.0.0"
212+
record = reader.isp(ip_address)
213+
self.assertEqual(record, eval(repr(record)), "ISP repr can be eval'd")
214+
215+
self.assertEqual(record.autonomous_system_number, 1221)
216+
self.assertEqual(record.autonomous_system_organization, "Telstra Pty Ltd")
217+
self.assertEqual(record.isp, "Telstra Internet")
218+
self.assertEqual(record.organization, "Telstra Internet")
219+
self.assertEqual(record.ip_address, ip_address)
220+
self.assertEqual(record.network, ipaddress.ip_network("1.128.0.0/11"))
221+
222+
self.assertRegex(
223+
str(record),
224+
r"ISP\(\{.*Telstra.*\}\)",
225+
"ISP str representation is reasonable",
226+
)
215227

216-
self.assertRegex(
217-
str(record),
218-
r"ISP\(\{.*Telstra.*\}\)",
219-
"ISP str representation is reasonable",
220-
)
228+
record = reader.isp("149.101.100.0")
221229

222-
reader.close()
230+
self.assertEqual(record.mobile_country_code, "310")
231+
self.assertEqual(record.mobile_network_code, "004")
223232

224233
def test_context_manager(self) -> None:
225234
with geoip2.database.Reader(

0 commit comments

Comments
 (0)
Please sign in to comment.