diff --git a/pyproject.toml b/pyproject.toml index 5befe70..8ab4217 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,6 +36,8 @@ classifiers = [ [project.optional-dependencies] test = [ + "pytest~=8.3", + "pytest-cov~=5.0", "pytest-httpserver>=1.0.10", ] diff --git a/setup.cfg b/setup.cfg index fb01367..a0000af 100644 --- a/setup.cfg +++ b/setup.cfg @@ -20,10 +20,8 @@ python = 3.12: py312,black,lint,flake8,mypy [testenv:{py38,py39,py310,py311,py312}-test] -deps = - pytest-httpserver - pytest -commands = pytest tests +commands = pytest tests {posargs:--cov --cov-report=term-missing} +extras = test [testenv:py312-black] deps = black diff --git a/tests/database_test.py b/tests/database_test.py index 73279dc..bfdb798 100644 --- a/tests/database_test.py +++ b/tests/database_test.py @@ -1,14 +1,8 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from __future__ import unicode_literals - import ipaddress -import sys -import unittest +import re from unittest.mock import patch, MagicMock -sys.path.append("..") +import pytest import geoip2.database import geoip2.errors @@ -20,7 +14,7 @@ maxminddb.extension = None # type: ignore -class TestReader(unittest.TestCase): +class TestReader: def test_language_list(self) -> None: reader = geoip2.database.Reader( "tests/data/test-data/GeoIP2-Country-Test.mmdb", @@ -28,43 +22,39 @@ def test_language_list(self) -> None: ) record = reader.country("81.2.69.160") - self.assertEqual(record.country.name, "Великобритания") + assert record.country.name == "Великобритания" reader.close() def test_unknown_address(self) -> None: reader = geoip2.database.Reader("tests/data/test-data/GeoIP2-City-Test.mmdb") - with self.assertRaisesRegex( + with pytest.raises( geoip2.errors.AddressNotFoundError, - "The address 10.10.10.10 is not in the " "database.", + match="The address 10.10.10.10 is not in the database.", ): reader.city("10.10.10.10") reader.close() def test_unknown_address_network(self) -> None: reader = geoip2.database.Reader("tests/data/test-data/GeoIP2-City-Test.mmdb") - try: + with pytest.raises(geoip2.errors.AddressNotFoundError) as ei: reader.city("10.10.10.10") - self.fail("Expected AddressNotFoundError") - except geoip2.errors.AddressNotFoundError as e: - self.assertEqual(e.network, ipaddress.ip_network("10.0.0.0/8")) - except Exception as e: - self.fail(f"Expected AddressNotFoundError, got {type(e)}: {str(e)}") - finally: - reader.close() + assert ei.value.network == ipaddress.ip_network("10.0.0.0/8") + reader.close() def test_wrong_database(self) -> None: reader = geoip2.database.Reader("tests/data/test-data/GeoIP2-City-Test.mmdb") - with self.assertRaisesRegex( + with pytest.raises( TypeError, - "The country method cannot be used with " "the GeoIP2-City database", + match="The country method cannot be used with the GeoIP2-City database", ): reader.country("1.1.1.1") reader.close() def test_invalid_address(self) -> None: reader = geoip2.database.Reader("tests/data/test-data/GeoIP2-City-Test.mmdb") - with self.assertRaisesRegex( - ValueError, "u?'invalid' does not appear to be an " "IPv4 or IPv6 address" + with pytest.raises( + ValueError, + match="u?'invalid' does not appear to be an " "IPv4 or IPv6 address", ): reader.city("invalid") reader.close() @@ -76,14 +66,14 @@ def test_anonymous_ip(self) -> None: ip_address = "1.2.0.1" record = reader.anonymous_ip(ip_address) - self.assertEqual(record.is_anonymous, True) - self.assertEqual(record.is_anonymous_vpn, True) - self.assertEqual(record.is_hosting_provider, False) - self.assertEqual(record.is_public_proxy, False) - self.assertEqual(record.is_residential_proxy, False) - self.assertEqual(record.is_tor_exit_node, False) - self.assertEqual(record.ip_address, ip_address) - self.assertEqual(record.network, ipaddress.ip_network("1.2.0.0/16")) + assert record.is_anonymous is True + assert record.is_anonymous_vpn is True + assert record.is_hosting_provider is False + assert record.is_public_proxy is False + assert record.is_residential_proxy is False + assert record.is_tor_exit_node is False + assert record.ip_address == ip_address + assert record.network == ipaddress.ip_network("1.2.0.0/16") reader.close() def test_anonymous_ip_all_set(self) -> None: @@ -93,14 +83,14 @@ def test_anonymous_ip_all_set(self) -> None: ip_address = "81.2.69.1" record = reader.anonymous_ip(ip_address) - self.assertEqual(record.is_anonymous, True) - self.assertEqual(record.is_anonymous_vpn, True) - self.assertEqual(record.is_hosting_provider, True) - self.assertEqual(record.is_public_proxy, True) - self.assertEqual(record.is_residential_proxy, True) - self.assertEqual(record.is_tor_exit_node, True) - self.assertEqual(record.ip_address, ip_address) - self.assertEqual(record.network, ipaddress.ip_network("81.2.69.0/24")) + assert record.is_anonymous is True + assert record.is_anonymous_vpn is True + assert record.is_hosting_provider is True + assert record.is_public_proxy is True + assert record.is_residential_proxy is True + assert record.is_tor_exit_node is True + assert record.ip_address == ip_address + assert record.network == ipaddress.ip_network("81.2.69.0/24") reader.close() def test_asn(self) -> None: @@ -109,18 +99,16 @@ def test_asn(self) -> None: ip_address = "1.128.0.0" record = reader.asn(ip_address) - self.assertEqual(record, eval(repr(record)), "ASN repr can be eval'd") + assert record == eval(repr(record)), "ASN repr can be eval'd" - self.assertEqual(record.autonomous_system_number, 1221) - self.assertEqual(record.autonomous_system_organization, "Telstra Pty Ltd") - self.assertEqual(record.ip_address, ip_address) - self.assertEqual(record.network, ipaddress.ip_network("1.128.0.0/11")) + assert record.autonomous_system_number == 1221 + assert record.autonomous_system_organization == "Telstra Pty Ltd" + assert record.ip_address == ip_address + assert record.network == ipaddress.ip_network("1.128.0.0/11") - self.assertRegex( - str(record), - r"geoip2.models.ASN\(.*1\.128\.0\.0.*\)", - "str representation is correct", - ) + assert re.search( + r"geoip2.models.ASN\(.*1\.128\.0\.0.*\)", str(record) + ), "str representation is correct" reader.close() @@ -128,18 +116,16 @@ def test_city(self) -> None: reader = geoip2.database.Reader("tests/data/test-data/GeoIP2-City-Test.mmdb") record = reader.city("81.2.69.160") - self.assertEqual( - record.country.name, "United Kingdom", "The default locale is en" - ) - self.assertEqual(record.country.is_in_european_union, False) - self.assertEqual( - record.location.accuracy_radius, 100, "The accuracy_radius is populated" - ) - self.assertEqual(record.registered_country.is_in_european_union, False) - self.assertFalse(record.traits.is_anycast) + assert record.country.name == "United Kingdom", "The default locale is en" + assert record.country.is_in_european_union is False + assert ( + record.location.accuracy_radius == 100 + ), "The accuracy_radius is populated" + assert record.registered_country.is_in_european_union is False + assert not record.traits.is_anycast record = reader.city("214.1.1.0") - self.assertTrue(record.traits.is_anycast) + assert record.traits.is_anycast reader.close() @@ -151,35 +137,27 @@ def test_connection_type(self) -> None: record = reader.connection_type(ip_address) - self.assertEqual( - record, eval(repr(record)), "ConnectionType repr can be eval'd" - ) - - self.assertEqual(record.connection_type, "Cellular") - self.assertEqual(record.ip_address, ip_address) - self.assertEqual(record.network, ipaddress.ip_network("1.0.1.0/24")) - - self.assertRegex( - str(record), - r"ConnectionType\(\{.*Cellular.*\}\)", - "ConnectionType str representation is reasonable", - ) + assert record == eval(repr(record)), "ConnectionType repr can be eval'd" + assert record.connection_type == "Cellular" + assert record.ip_address == ip_address + assert record.network == ipaddress.ip_network("1.0.1.0/24") + assert re.search( + r"ConnectionType\(\{.*Cellular.*\}\)", str(record) + ), "ConnectionType str representation is reasonable" reader.close() def test_country(self) -> None: reader = geoip2.database.Reader("tests/data/test-data/GeoIP2-Country-Test.mmdb") record = reader.country("81.2.69.160") - self.assertEqual( - record.traits.ip_address, "81.2.69.160", "IP address is added to model" - ) - self.assertEqual(record.traits.network, ipaddress.ip_network("81.2.69.160/27")) - self.assertEqual(record.country.is_in_european_union, False) - self.assertEqual(record.registered_country.is_in_european_union, False) - self.assertFalse(record.traits.is_anycast) + assert record.traits.ip_address == "81.2.69.160", "IP address is added to model" + assert record.traits.network == ipaddress.ip_network("81.2.69.160/27") + assert record.country.is_in_european_union is False + assert record.registered_country.is_in_european_union is False + assert not record.traits.is_anycast record = reader.country("214.1.1.0") - self.assertTrue(record.traits.is_anycast) + assert record.traits.is_anycast reader.close() @@ -189,17 +167,14 @@ def test_domain(self) -> None: ip_address = "1.2.0.0" record = reader.domain(ip_address) - self.assertEqual(record, eval(repr(record)), "Domain repr can be eval'd") + assert record == eval(repr(record)), "Domain repr can be eval'd" - self.assertEqual(record.domain, "maxmind.com") - self.assertEqual(record.ip_address, ip_address) - self.assertEqual(record.network, ipaddress.ip_network("1.2.0.0/16")) - - self.assertRegex( - str(record), - r"Domain\(\{.*maxmind.com.*\}\)", - "Domain str representation is reasonable", - ) + assert record.domain == "maxmind.com" + assert record.ip_address == ip_address + assert record.network == ipaddress.ip_network("1.2.0.0/16") + assert re.search( + r"Domain\(\{.*maxmind.com.*\}\)", str(record) + ), "Domain str representation is reasonable" reader.close() @@ -209,26 +184,24 @@ def test_enterprise(self) -> None: ) as reader: ip_address = "74.209.24.0" record = reader.enterprise(ip_address) - self.assertEqual(record.city.confidence, 11) - self.assertEqual(record.country.confidence, 99) - self.assertEqual(record.country.geoname_id, 6252001) - self.assertEqual(record.country.is_in_european_union, False) - self.assertEqual(record.location.accuracy_radius, 27) - self.assertEqual(record.registered_country.is_in_european_union, False) - self.assertEqual(record.traits.connection_type, "Cable/DSL") - self.assertTrue(record.traits.is_legitimate_proxy) - self.assertEqual(record.traits.ip_address, ip_address) - self.assertEqual( - record.traits.network, ipaddress.ip_network("74.209.16.0/20") - ) - self.assertFalse(record.traits.is_anycast) + assert record.city.confidence == 11 + assert record.country.confidence == 99 + assert record.country.geoname_id == 6252001 + assert record.country.is_in_european_union is False + assert record.location.accuracy_radius == 27 + assert record.registered_country.is_in_european_union is False + assert record.traits.connection_type == "Cable/DSL" + assert record.traits.is_legitimate_proxy + assert record.traits.ip_address == ip_address + assert record.traits.network == ipaddress.ip_network("74.209.16.0/20") + assert not record.traits.is_anycast record = reader.enterprise("149.101.100.0") - self.assertEqual(record.traits.mobile_country_code, "310") - self.assertEqual(record.traits.mobile_network_code, "004") + assert record.traits.mobile_country_code == "310" + assert record.traits.mobile_network_code == "004" record = reader.enterprise("214.1.1.0") - self.assertTrue(record.traits.is_anycast) + assert record.traits.is_anycast def test_isp(self) -> None: with geoip2.database.Reader( @@ -236,32 +209,35 @@ def test_isp(self) -> None: ) as reader: ip_address = "1.128.0.0" record = reader.isp(ip_address) - self.assertEqual(record, eval(repr(record)), "ISP repr can be eval'd") - - self.assertEqual(record.autonomous_system_number, 1221) - self.assertEqual(record.autonomous_system_organization, "Telstra Pty Ltd") - self.assertEqual(record.isp, "Telstra Internet") - self.assertEqual(record.organization, "Telstra Internet") - self.assertEqual(record.ip_address, ip_address) - self.assertEqual(record.network, ipaddress.ip_network("1.128.0.0/11")) - - self.assertRegex( - str(record), - r"ISP\(\{.*Telstra.*\}\)", - "ISP str representation is reasonable", - ) - + assert record == eval(repr(record)), "ISP repr can be eval'd" + + assert record.autonomous_system_number == 1221 + assert record.autonomous_system_organization == "Telstra Pty Ltd" + assert record.isp == "Telstra Internet" + assert record.organization == "Telstra Internet" + assert record.ip_address == ip_address + assert record.network == ipaddress.ip_network("1.128.0.0/11") + assert re.search( + r"ISP\(\{.*Telstra.*\}\)", str(record) + ), "ISP str representation is reasonable" record = reader.isp("149.101.100.0") - self.assertEqual(record.mobile_country_code, "310") - self.assertEqual(record.mobile_network_code, "004") + assert record.mobile_country_code == "310" + assert record.mobile_network_code == "004" def test_context_manager(self) -> None: with geoip2.database.Reader( "tests/data/test-data/GeoIP2-Country-Test.mmdb" ) as reader: record = reader.country("81.2.69.160") - self.assertEqual(record.traits.ip_address, "81.2.69.160") + assert record.traits.ip_address == "81.2.69.160" + + def test_metadata(self) -> None: + with geoip2.database.Reader( + "tests/data/test-data/GeoIP2-Country-Test.mmdb" + ) as reader: + meta = reader.metadata() + assert meta.database_type == "GeoIP2-Country" @patch("maxminddb.open_database") def test_modes(self, mock_open) -> None: @@ -271,5 +247,5 @@ def test_modes(self, mock_open) -> None: with geoip2.database.Reader( path, mode=geoip2.database.MODE_MMAP_EXT, - ) as reader: + ): mock_open.assert_called_once_with(path, geoip2.database.MODE_MMAP_EXT) diff --git a/tests/models_test.py b/tests/models_test.py index 9f4fa72..3cd805b 100644 --- a/tests/models_test.py +++ b/tests/models_test.py @@ -1,18 +1,12 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- +import re -from __future__ import unicode_literals - -import sys +import pytest from typing import Dict -import unittest - -sys.path.append("..") import geoip2.models -class TestModels(unittest.TestCase): +class TestModels: def test_insights_full(self) -> None: raw = { "city": { @@ -94,154 +88,108 @@ def test_insights_full(self) -> None: } model = geoip2.models.Insights(raw) - self.assertEqual( - type(model), geoip2.models.Insights, "geoip2.models.Insights object" - ) - self.assertEqual( - type(model.city), geoip2.records.City, "geoip2.records.City object" - ) - self.assertEqual( - type(model.continent), - geoip2.records.Continent, - "geoip2.records.Continent object", - ) - self.assertEqual( - type(model.country), geoip2.records.Country, "geoip2.records.Country object" - ) - self.assertEqual( - type(model.registered_country), - geoip2.records.Country, - "geoip2.records.Country object", - ) - self.assertEqual( - type(model.represented_country), - geoip2.records.RepresentedCountry, - "geoip2.records.RepresentedCountry object", - ) - self.assertEqual( - type(model.location), - geoip2.records.Location, - "geoip2.records.Location object", - ) - self.assertEqual( - type(model.subdivisions[0]), - geoip2.records.Subdivision, - "geoip2.records.Subdivision object", - ) - self.assertEqual( - type(model.traits), geoip2.records.Traits, "geoip2.records.Traits object" - ) - self.assertEqual(model.raw, raw, "raw method returns raw input") - self.assertEqual( - model.subdivisions[0].iso_code, "MN", "div 1 has correct iso_code" - ) - self.assertEqual( - model.subdivisions[0].confidence, 88, "div 1 has correct confidence" - ) - self.assertEqual( - model.subdivisions[0].geoname_id, 574635, "div 1 has correct geoname_id" - ) - self.assertEqual( - model.subdivisions[0].names, {"en": "Minnesota"}, "div 1 names are correct" - ) - self.assertEqual( - model.subdivisions[1].name, "Hennepin", "div 2 has correct name" - ) - self.assertEqual( - model.subdivisions.most_specific.iso_code, - "HP", - "subdivisions.most_specific returns HP", - ) - self.assertEqual( - model.represented_country.name, - "United Kingdom", - "represented_country name is correct", - ) - self.assertEqual( - model.represented_country.type, - "military", - "represented_country type is correct", - ) - self.assertEqual(model.location.average_income, 24626, "correct average_income") - self.assertEqual(model.location.latitude, 44.98, "correct latitude") - self.assertEqual(model.location.longitude, 93.2636, "correct longitude") - self.assertEqual(model.location.metro_code, 765, "correct metro_code") - self.assertEqual( - model.location.population_density, 1341, "correct population_density" - ) - - self.assertRegex( - str(model), - r"^geoip2.models.Insights\(\{.*geoname_id.*\}, \[.*en.*\]\)", - "Insights str representation looks reasonable", - ) - - self.assertEqual(model, eval(repr(model)), "Insights repr can be eval'd") - - self.assertRegex( - str(model.location), - r"^geoip2.records.Location\(.*longitude=.*\)", - "Location str representation is reasonable", - ) + assert isinstance( + model, geoip2.models.Insights + ), "geoip2.models.Insights object" + assert isinstance(model.city, geoip2.records.City), "geoip2.records.City object" + assert isinstance( + model.continent, geoip2.records.Continent + ), "geoip2.records.Continent object" + assert isinstance( + model.country, geoip2.records.Country + ), "geoip2.records.Country object" + assert isinstance( + model.registered_country, geoip2.records.Country + ), "geoip2.records.Country object" + assert isinstance( + model.represented_country, geoip2.records.RepresentedCountry + ), "geoip2.records.RepresentedCountry object" + assert isinstance( + model.location, geoip2.records.Location + ), "geoip2.records.Location object" + assert isinstance( + model.subdivisions[0], geoip2.records.Subdivision + ), "geoip2.records.Subdivision object" + assert isinstance( + model.traits, geoip2.records.Traits + ), "geoip2.records.Traits object" + assert model.raw == raw, "raw method returns raw input" + assert model.subdivisions[0].iso_code == "MN", "div 1 has correct iso_code" + assert model.subdivisions[0].confidence == 88, "div 1 has correct confidence" + assert ( + model.subdivisions[0].geoname_id == 574635 + ), "div 1 has correct geoname_id" + assert model.subdivisions[0].names == { + "en": "Minnesota" + }, "div 1 names are correct" + assert model.subdivisions[1].name == "Hennepin", "div 2 has correct name" + assert ( + model.subdivisions.most_specific.iso_code == "HP" + ), "subdivisions.most_specific returns HP" + assert ( + model.represented_country.name == "United Kingdom" + ), "represented_country name is correct" + assert ( + model.represented_country.type == "military" + ), "represented_country type is correct" + assert model.location.average_income == 24626, "correct average_income" + assert model.location.latitude == 44.98, "correct latitude" + assert model.location.longitude == 93.2636, "correct longitude" + assert model.location.metro_code == 765, "correct metro_code" + assert model.location.population_density == 1341, "correct population_density" + assert re.search( + r"^geoip2.models.Insights\(\{.*geoname_id.*\}, \[.*en.*\]\)", str(model) + ), "Insights str representation looks reasonable" + assert model == eval(repr(model)), "Insights repr can be eval'd" + assert re.search( + r"^geoip2.records.Location\(.*longitude=.*\)", str(model.location) + ), "Location str representation is reasonable" - self.assertEqual( - model.location, eval(repr(model.location)), "Location repr can be eval'd" - ) + assert model.location == eval( + repr(model.location) + ), "Location repr can be eval'd" - self.assertIs(model.country.is_in_european_union, False) - self.assertIs(model.registered_country.is_in_european_union, False) - self.assertIs(model.represented_country.is_in_european_union, True) + assert model.country.is_in_european_union is False + assert model.registered_country.is_in_european_union is False + assert model.represented_country.is_in_european_union is True - self.assertIs(model.traits.is_anonymous, True) - self.assertIs(model.traits.is_anonymous_proxy, True) - self.assertIs(model.traits.is_anonymous_vpn, True) - self.assertIs(model.traits.is_anycast, True) - self.assertIs(model.traits.is_hosting_provider, True) - self.assertIs(model.traits.is_public_proxy, True) - self.assertIs(model.traits.is_residential_proxy, True) - self.assertIs(model.traits.is_satellite_provider, True) - self.assertIs(model.traits.is_tor_exit_node, True) - self.assertEqual(model.traits.user_count, 2) - self.assertEqual(model.traits.static_ip_score, 1.3) + assert model.traits.is_anonymous is True + assert model.traits.is_anonymous_proxy is True + assert model.traits.is_anonymous_vpn is True + assert model.traits.is_anycast is True + assert model.traits.is_hosting_provider is True + assert model.traits.is_public_proxy is True + assert model.traits.is_residential_proxy is True + assert model.traits.is_satellite_provider is True + assert model.traits.is_tor_exit_node is True + assert model.traits.user_count == 2 + assert model.traits.static_ip_score == 1.3 def test_insights_min(self) -> None: model = geoip2.models.Insights({"traits": {"ip_address": "5.6.7.8"}}) - self.assertEqual( - type(model), geoip2.models.Insights, "geoip2.models.Insights object" - ) - self.assertEqual( - type(model.city), geoip2.records.City, "geoip2.records.City object" - ) - self.assertEqual( - type(model.continent), - geoip2.records.Continent, - "geoip2.records.Continent object", - ) - self.assertEqual( - type(model.country), geoip2.records.Country, "geoip2.records.Country object" - ) - self.assertEqual( - type(model.registered_country), - geoip2.records.Country, - "geoip2.records.Country object", - ) - self.assertEqual( - type(model.location), - geoip2.records.Location, - "geoip2.records.Location object", - ) - self.assertEqual( - type(model.traits), geoip2.records.Traits, "geoip2.records.Traits object" - ) - self.assertEqual( - type(model.subdivisions.most_specific), - geoip2.records.Subdivision, - "geoip2.records.Subdivision object returned even" - "when none are available.", - ) - self.assertEqual( - model.subdivisions.most_specific.names, {}, "Empty names hash returned" - ) + assert isinstance( + model, geoip2.models.Insights + ), "geoip2.models.Insights object" + assert isinstance(model.city, geoip2.records.City), "geoip2.records.City object" + assert isinstance( + model.continent, geoip2.records.Continent + ), "geoip2.records.Continent object" + assert isinstance( + model.country, geoip2.records.Country + ), "geoip2.records.Country object" + assert isinstance( + model.registered_country, geoip2.records.Country + ), "geoip2.records.Country object" + assert isinstance( + model.location, geoip2.records.Location + ), "geoip2.records.Location object" + assert isinstance( + model.traits, geoip2.records.Traits + ), "geoip2.records.Traits object" + assert isinstance( + model.subdivisions.most_specific, geoip2.records.Subdivision + ), "geoip2.records.Subdivision object returned evenwhen none are available." + assert model.subdivisions.most_specific.names == {}, "Empty names hash returned" def test_city_full(self) -> None: raw = { @@ -266,86 +214,62 @@ def test_city_full(self) -> None: }, } model = geoip2.models.City(raw) - self.assertEqual(type(model), geoip2.models.City, "geoip2.models.City object") - self.assertEqual( - type(model.city), geoip2.records.City, "geoip2.records.City object" - ) - self.assertEqual( - type(model.continent), - geoip2.records.Continent, - "geoip2.records.Continent object", - ) - self.assertEqual( - type(model.country), geoip2.records.Country, "geoip2.records.Country object" - ) - self.assertEqual( - type(model.registered_country), - geoip2.records.Country, - "geoip2.records.Country object", - ) - self.assertEqual( - type(model.location), - geoip2.records.Location, - "geoip2.records.Location object", - ) - self.assertEqual( - type(model.traits), geoip2.records.Traits, "geoip2.records.Traits object" - ) - self.assertEqual(model.raw, raw, "raw method returns raw input") - self.assertEqual(model.continent.geoname_id, 42, "continent geoname_id is 42") - self.assertEqual(model.continent.code, "NA", "continent code is NA") - self.assertEqual( - model.continent.names, {"en": "North America"}, "continent names is correct" - ) - self.assertEqual( - model.continent.name, "North America", "continent name is correct" - ) - self.assertEqual(model.country.geoname_id, 1, "country geoname_id is 1") - self.assertEqual(model.country.iso_code, "US", "country iso_code is US") - self.assertEqual( - model.country.names, - {"en": "United States of America"}, - "country names is correct", - ) - self.assertEqual( - model.country.name, "United States of America", "country name is correct" - ) - self.assertEqual(model.country.confidence, None, "country confidence is None") - self.assertEqual( - model.registered_country.iso_code, "CA", "registered_country iso_code is CA" - ) - self.assertEqual( - model.registered_country.names, - {"en": "Canada"}, - "registered_country names is correct", - ) - self.assertEqual( - model.registered_country.name, - "Canada", - "registered_country name is correct", - ) - self.assertEqual( - model.traits.is_anonymous_proxy, - False, - "traits is_anonymous_proxy returns False by default", - ) - self.assertEqual( - model.traits.is_anycast, - False, - "traits is_anycast returns False by default", - ) - self.assertEqual( - model.traits.is_satellite_provider, - True, - "traits is_setellite_provider is True", - ) - self.assertEqual(model.raw, raw, "raw method produces raw output") - - self.assertRegex( - str(model), r"^geoip2.models.City\(\{.*geoname_id.*\}, \[.*en.*\]\)" - ) - - self.assertFalse(model == True, "__eq__ does not blow up on weird input") + assert isinstance(model, geoip2.models.City), "geoip2.models.City object" + assert isinstance(model.city, geoip2.records.City), "geoip2.records.City object" + assert isinstance( + model.continent, geoip2.records.Continent + ), "geoip2.records.Continent object" + assert isinstance( + model.country, geoip2.records.Country + ), "geoip2.records.Country object" + assert isinstance( + model.registered_country, geoip2.records.Country + ), "geoip2.records.Country object" + assert isinstance( + model.location, geoip2.records.Location + ), "geoip2.records.Location object" + assert isinstance( + model.traits, geoip2.records.Traits + ), "geoip2.records.Traits object" + assert model.raw == raw, "raw method returns raw input" + assert model.continent.geoname_id == 42, "continent geoname_id is 42" + assert model.continent.code == "NA", "continent code is NA" + assert model.continent.names == { + "en": "North America" + }, "continent names is correct" + assert model.continent.name == "North America", "continent name is correct" + assert model.country.geoname_id == 1, "country geoname_id is 1" + assert model.country.iso_code == "US", "country iso_code is US" + assert model.country.names == { + "en": "United States of America" + }, "country names is correct" + assert ( + model.country.name == "United States of America" + ), "country name is correct" + assert model.country.confidence is None, "country confidence is None" + assert ( + model.registered_country.iso_code == "CA" + ), "registered_country iso_code is CA" + assert model.registered_country.names == { + "en": "Canada" + }, "registered_country names is correct" + assert ( + model.registered_country.name == "Canada" + ), "registered_country name is correct" + assert ( + model.traits.is_anonymous_proxy is False + ), "traits is_anonymous_proxy returns False by default" + assert ( + model.traits.is_anycast is False + ), "traits is_anycast returns False by default" + assert ( + model.traits.is_satellite_provider is True + ), "traits is_setellite_provider is True" + assert model.raw == raw, "raw method produces raw output" + assert re.search( + r"^geoip2.models.City\(\{.*geoname_id.*\}, \[.*en.*\]\)", str(model) + ), "City str representation looks reasonable" + assert not (model == 8), "__eq__ does not blow up on weird input" def test_unknown_keys(self) -> None: model = geoip2.models.City( @@ -385,14 +309,14 @@ def test_unknown_keys(self) -> None: "unk_base": {"blah": 1}, } ) - with self.assertRaises(AttributeError): + with pytest.raises(AttributeError): model.unk_base # type: ignore - with self.assertRaises(AttributeError): + with pytest.raises(AttributeError): model.traits.invalid # type: ignore - self.assertEqual(model.traits.ip_address, "1.2.3.4", "correct ip") + assert model.traits.ip_address == "1.2.3.4", "correct ip" -class TestNames(unittest.TestCase): +class TestNames: raw: Dict = { "continent": { "code": "NA", @@ -423,50 +347,36 @@ class TestNames(unittest.TestCase): def test_names(self) -> None: model = geoip2.models.Country(self.raw, locales=["sq", "ar"]) - self.assertEqual( - model.continent.names, - self.raw["continent"]["names"], - "Correct names dict for continent", - ) - self.assertEqual( - model.country.names, - self.raw["country"]["names"], - "Correct names dict for country", - ) + assert ( + model.continent.names == self.raw["continent"]["names"] + ), "Correct names dict for continent" + assert ( + model.country.names == self.raw["country"]["names"] + ), "Correct names dict for country" def test_three_locales(self) -> None: model = geoip2.models.Country(self.raw, locales=["fr", "zh-CN", "en"]) - self.assertEqual( - model.continent.name, - "北美洲", - "continent name is in Chinese (no French available)", - ) - self.assertEqual(model.country.name, "États-Unis", "country name is in French") + assert ( + model.continent.name == "北美洲" + ), "continent name is in Chinese (no French available)" + assert model.country.name == "États-Unis", "country name is in French" def test_two_locales(self) -> None: model = geoip2.models.Country(self.raw, locales=["ak", "fr"]) - self.assertEqual( - model.continent.name, - None, - "continent name is undef (no Akan or French " "available)", - ) - self.assertEqual(model.country.name, "États-Unis", "country name is in French") + assert ( + model.continent.name is None + ), "continent name is undef (no Akan or French available)" + assert model.country.name == "États-Unis", "country name is in French" def test_unknown_locale(self) -> None: model = geoip2.models.Country(self.raw, locales=["aa"]) - self.assertEqual( - model.continent.name, None, "continent name is undef (no Afar available)" - ) - self.assertEqual( - model.country.name, None, "country name is in None (no Afar available)" - ) + assert ( + model.continent.name is None + ), "continent name is undef (no Afar available)" + assert model.country.name is None, "country name is in None (no Afar available)" def test_german(self) -> None: model = geoip2.models.Country(self.raw, locales=["de"]) - self.assertEqual( - model.continent.name, "Nordamerika", "Correct german name for continent" - ) - - -if __name__ == "__main__": - unittest.main() + assert ( + model.continent.name == "Nordamerika" + ), "Correct german name for continent" diff --git a/tests/webservice_test.py b/tests/webservice_test.py index 813738f..898d494 100644 --- a/tests/webservice_test.py +++ b/tests/webservice_test.py @@ -1,11 +1,7 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - import asyncio import copy import ipaddress -import json -import sys +from contextlib import ExitStack, AsyncExitStack from typing import cast, Dict import unittest from pytest_httpserver import HeaderValueMatcher @@ -14,7 +10,6 @@ from collections import defaultdict -sys.path.append("..") import geoip2 from geoip2.errors import ( AddressNotFoundError, @@ -76,42 +71,32 @@ def test_country_ok(self): content_type=self._content_type("country"), ) country = self.run_client(self.client.country("1.2.3.4")) - self.assertEqual( - type(country), geoip2.models.Country, "return value of client.country" - ) - self.assertEqual(country.continent.geoname_id, 42, "continent geoname_id is 42") - self.assertEqual(country.continent.code, "NA", "continent code is NA") - self.assertEqual( - country.continent.name, "North America", "continent name is North America" - ) - self.assertEqual(country.country.geoname_id, 1, "country geoname_id is 1") - self.assertIs( - country.country.is_in_european_union, - False, - "country is_in_european_union is False", - ) - self.assertEqual(country.country.iso_code, "US", "country iso_code is US") - self.assertEqual( - country.country.names, {"en": "United States of America"}, "country names" - ) - self.assertEqual( - country.country.name, - "United States of America", - "country name is United States of America", - ) - self.assertEqual( - country.maxmind.queries_remaining, 11, "queries_remaining is 11" - ) - self.assertIs( - country.registered_country.is_in_european_union, - True, - "registered_country is_in_european_union is True", - ) - self.assertEqual( - country.traits.network, ipaddress.ip_network("1.2.3.0/24"), "network" - ) - self.assertTrue(country.traits.is_anycast) - self.assertEqual(country.raw, self.country, "raw response is correct") + assert isinstance( + country, geoip2.models.Country + ), "return value of client.country" + assert country.continent.geoname_id == 42, "continent geoname_id is 42" + assert country.continent.code == "NA", "continent code is NA" + assert ( + country.continent.name == "North America" + ), "continent name is North America" + assert country.country.geoname_id == 1, "country geoname_id is 1" + assert ( + country.country.is_in_european_union is False + ), "country is_in_european_union is False" + assert country.country.iso_code == "US", "country iso_code is US" + assert country.country.names == { + "en": "United States of America" + }, "country names" + assert ( + country.country.name == "United States of America" + ), "country name is United States of America" + assert country.maxmind.queries_remaining == 11, "queries_remaining is 11" + assert ( + country.registered_country.is_in_european_union is True + ), "registered_country is_in_european_union is True" + assert country.traits.network == ipaddress.ip_network("1.2.3.0/24"), "network" + assert country.traits.is_anycast + assert country.raw == self.country, "raw response is correct" def test_me(self): self.httpserver.expect_request( @@ -122,15 +107,13 @@ def test_me(self): content_type=self._content_type("country"), ) implicit_me = self.run_client(self.client.country()) - self.assertEqual( - type(implicit_me), geoip2.models.Country, "country() returns Country object" - ) + assert isinstance( + implicit_me, geoip2.models.Country + ), "country() returns Country object" explicit_me = self.run_client(self.client.country()) - self.assertEqual( - type(explicit_me), - geoip2.models.Country, - "country('me') returns Country object", - ) + assert isinstance( + explicit_me, geoip2.models.Country + ), "country('me') returns Country object" def test_200_error(self): self.httpserver.expect_request( @@ -141,14 +124,12 @@ def test_200_error(self): content_type=self._content_type("country"), ) - with self.assertRaisesRegex( - GeoIP2Error, "could not decode the response as JSON" - ): + with pytest.raises(GeoIP2Error, match="could not decode the response as JSON"): self.run_client(self.client.country("1.1.1.1")) def test_bad_ip_address(self): - with self.assertRaisesRegex( - ValueError, "'1.2.3' does not appear to be an IPv4 " "or IPv6 address" + with pytest.raises( + ValueError, match="'1.2.3' does not appear to be an IPv4 or IPv6 address" ): self.run_client(self.client.country("1.2.3")) @@ -160,9 +141,7 @@ def test_no_body_error(self): status=400, content_type=self._content_type("country"), ) - with self.assertRaisesRegex( - HTTPError, "Received a 400 error for .* with no body" - ): + with pytest.raises(HTTPError, match="Received a 400 error for .* with no body"): self.run_client(self.client.country("1.2.3.7")) def test_weird_body_error(self): @@ -175,9 +154,10 @@ def test_weird_body_error(self): content_type=self._content_type("country"), ) - with self.assertRaisesRegex( + with pytest.raises( HTTPError, - "Response contains JSON but it does not " "specify code or error keys", + match="Response contains JSON but it does not " + "specify code or error keys", ): self.run_client(self.client.country("1.2.3.8")) @@ -190,8 +170,8 @@ def test_bad_body_error(self): status=400, content_type=self._content_type("country"), ) - with self.assertRaisesRegex( - HTTPError, "it did not include the expected JSON body" + with pytest.raises( + HTTPError, match="it did not include the expected JSON body" ): self.run_client(self.client.country("1.2.3.9")) @@ -203,7 +183,7 @@ def test_500_error(self): status=500, content_type=self._content_type("country"), ) - with self.assertRaisesRegex(HTTPError, r"Received a server error \(500\) for"): + with pytest.raises(HTTPError, match=r"Received a server error \(500\) for"): self.run_client(self.client.country("1.2.3.10")) def test_300_error(self): @@ -215,8 +195,8 @@ def test_300_error(self): status=300, content_type=self._content_type("country"), ) - with self.assertRaisesRegex( - HTTPError, r"Received a very surprising HTTP status \(300\) for" + with pytest.raises( + HTTPError, match=r"Received a very surprising HTTP status \(300\) for" ): self.run_client(self.client.country("1.2.3.11")) @@ -263,7 +243,7 @@ def _test_error(self, status, error_code, error_class): status=status, content_type=self._content_type("country"), ) - with self.assertRaisesRegex(error_class, msg): + with pytest.raises(error_class, match=msg): self.run_client(self.client.country("1.2.3.18")) def test_unknown_error(self): @@ -277,7 +257,7 @@ def test_unknown_error(self): status=400, content_type=self._content_type("country"), ) - with self.assertRaisesRegex(InvalidRequestError, msg): + with pytest.raises(InvalidRequestError, match=msg): self.run_client(self.client.country(ip)) def test_request(self): @@ -316,11 +296,9 @@ def test_city_ok(self): content_type=self._content_type("city"), ) city = self.run_client(self.client.city("1.2.3.4")) - self.assertEqual(type(city), geoip2.models.City, "return value of client.city") - self.assertEqual( - city.traits.network, ipaddress.ip_network("1.2.3.0/24"), "network" - ) - self.assertTrue(city.traits.is_anycast) + assert isinstance(city, geoip2.models.City), "return value of client.city" + assert city.traits.network == ipaddress.ip_network("1.2.3.0/24"), "network" + assert city.traits.is_anycast def test_insights_ok(self): self.httpserver.expect_request( @@ -331,36 +309,39 @@ def test_insights_ok(self): content_type=self._content_type("insights"), ) insights = self.run_client(self.client.insights("1.2.3.4")) - self.assertEqual( - type(insights), geoip2.models.Insights, "return value of client.insights" - ) - self.assertEqual( - insights.traits.network, ipaddress.ip_network("1.2.3.0/24"), "network" - ) - self.assertTrue(insights.traits.is_anycast) - self.assertEqual(insights.traits.static_ip_score, 1.3, "static_ip_score is 1.3") - self.assertEqual(insights.traits.user_count, 2, "user_count is 2") + assert isinstance( + insights, geoip2.models.Insights + ), "return value of client.insights" + assert insights.traits.network == ipaddress.ip_network("1.2.3.0/24"), "network" + assert insights.traits.is_anycast + assert insights.traits.static_ip_score == 1.3, "static_ip_score is 1.3" + assert insights.traits.user_count == 2, "user_count is 2" def test_named_constructor_args(self): id = 47 key = "1234567890ab" client = self.client_class(account_id=id, license_key=key) - self.assertEqual(client._account_id, str(id)) - self.assertEqual(client._license_key, key) + assert client._account_id == str(id) + assert client._license_key == key def test_missing_constructor_args(self): - with self.assertRaises(TypeError): + with pytest.raises(TypeError): self.client_class(license_key="1234567890ab") - with self.assertRaises(TypeError): + with pytest.raises(TypeError): self.client_class("47") class TestClient(TestBaseClient): def setUp(self): + self.stack = ExitStack() self.client_class = Client self.client = Client(42, "abcdef123456") self.client._base_uri = self.httpserver.url_for("/geoip/v2.1") + self.stack.enter_context(self.client) + + def tearDown(self): + self.stack.close() def run_client(self, v): return v @@ -368,12 +349,15 @@ def run_client(self, v): class TestAsyncClient(TestBaseClient): def setUp(self): + self.stack = AsyncExitStack() self._loop = asyncio.new_event_loop() self.client_class = AsyncClient self.client = AsyncClient(42, "abcdef123456") self.client._base_uri = self.httpserver.url_for("/geoip/v2.1") + self._loop.run_until_complete(self.stack.enter_async_context(self.client)) def tearDown(self): + self._loop.run_until_complete(self.stack.aclose()) self._loop.run_until_complete(self.client.close()) self._loop.close() @@ -382,7 +366,3 @@ def run_client(self, v): del TestBaseClient - - -if __name__ == "__main__": - unittest.main()