1""" 2Models 3====== 4 5These classes provide models for the data returned by the GeoIP2 6web service and databases. 7 8The only difference between the City and Insights model classes is which 9fields in each record may be populated. See 10http://dev.maxmind.com/geoip/geoip2/web-services for more details. 11 12""" 13# pylint: disable=too-many-instance-attributes,too-few-public-methods 14import ipaddress 15from abc import ABCMeta 16from typing import Any, cast, Dict, List, Optional, Union 17 18import geoip2.records 19from geoip2.mixins import SimpleEquality 20 21 22class Country(SimpleEquality): 23 """Model for the GeoIP2 Precision: Country and the GeoIP2 Country database. 24 25 This class provides the following attributes: 26 27 .. attribute:: continent 28 29 Continent object for the requested IP address. 30 31 :type: :py:class:`geoip2.records.Continent` 32 33 .. attribute:: country 34 35 Country object for the requested IP address. This record represents the 36 country where MaxMind believes the IP is located. 37 38 :type: :py:class:`geoip2.records.Country` 39 40 .. attribute:: maxmind 41 42 Information related to your MaxMind account. 43 44 :type: :py:class:`geoip2.records.MaxMind` 45 46 .. attribute:: registered_country 47 48 The registered country object for the requested IP address. This record 49 represents the country where the ISP has registered a given IP block in 50 and may differ from the user's country. 51 52 :type: :py:class:`geoip2.records.Country` 53 54 .. attribute:: represented_country 55 56 Object for the country represented by the users of the IP address 57 when that country is different than the country in ``country``. For 58 instance, the country represented by an overseas military base. 59 60 :type: :py:class:`geoip2.records.RepresentedCountry` 61 62 .. attribute:: traits 63 64 Object with the traits of the requested IP address. 65 66 :type: :py:class:`geoip2.records.Traits` 67 68 """ 69 70 continent: geoip2.records.Continent 71 country: geoip2.records.Country 72 maxmind: geoip2.records.MaxMind 73 registered_country: geoip2.records.Country 74 represented_country: geoip2.records.RepresentedCountry 75 traits: geoip2.records.Traits 76 77 def __init__( 78 self, raw_response: Dict[str, Any], locales: Optional[List[str]] = None 79 ) -> None: 80 if locales is None: 81 locales = ["en"] 82 self._locales = locales 83 self.continent = geoip2.records.Continent( 84 locales, **raw_response.get("continent", {}) 85 ) 86 self.country = geoip2.records.Country( 87 locales, **raw_response.get("country", {}) 88 ) 89 self.registered_country = geoip2.records.Country( 90 locales, **raw_response.get("registered_country", {}) 91 ) 92 self.represented_country = geoip2.records.RepresentedCountry( 93 locales, **raw_response.get("represented_country", {}) 94 ) 95 96 self.maxmind = geoip2.records.MaxMind(**raw_response.get("maxmind", {})) 97 98 self.traits = geoip2.records.Traits(**raw_response.get("traits", {})) 99 self.raw = raw_response 100 101 def __repr__(self) -> str: 102 return ( 103 f"{self.__module__}.{self.__class__.__name__}({self.raw}, {self._locales})" 104 ) 105 106 107class City(Country): 108 """Model for the GeoIP2 Precision: City and the GeoIP2 City database. 109 110 .. attribute:: city 111 112 City object for the requested IP address. 113 114 :type: :py:class:`geoip2.records.City` 115 116 .. attribute:: continent 117 118 Continent object for the requested IP address. 119 120 :type: :py:class:`geoip2.records.Continent` 121 122 .. attribute:: country 123 124 Country object for the requested IP address. This record represents the 125 country where MaxMind believes the IP is located. 126 127 :type: :py:class:`geoip2.records.Country` 128 129 .. attribute:: location 130 131 Location object for the requested IP address. 132 133 :type: :py:class:`geoip2.records.Location` 134 135 .. attribute:: maxmind 136 137 Information related to your MaxMind account. 138 139 :type: :py:class:`geoip2.records.MaxMind` 140 141 .. attribute:: postal 142 143 Postal object for the requested IP address. 144 145 :type: :py:class:`geoip2.records.Postal` 146 147 .. attribute:: registered_country 148 149 The registered country object for the requested IP address. This record 150 represents the country where the ISP has registered a given IP block in 151 and may differ from the user's country. 152 153 :type: :py:class:`geoip2.records.Country` 154 155 .. attribute:: represented_country 156 157 Object for the country represented by the users of the IP address 158 when that country is different than the country in ``country``. For 159 instance, the country represented by an overseas military base. 160 161 :type: :py:class:`geoip2.records.RepresentedCountry` 162 163 .. attribute:: subdivisions 164 165 Object (tuple) representing the subdivisions of the country to which 166 the location of the requested IP address belongs. 167 168 :type: :py:class:`geoip2.records.Subdivisions` 169 170 .. attribute:: traits 171 172 Object with the traits of the requested IP address. 173 174 :type: :py:class:`geoip2.records.Traits` 175 176 """ 177 178 city: geoip2.records.City 179 location: geoip2.records.Location 180 postal: geoip2.records.Postal 181 subdivisions: geoip2.records.Subdivisions 182 183 def __init__( 184 self, raw_response: Dict[str, Any], locales: Optional[List[str]] = None 185 ) -> None: 186 super().__init__(raw_response, locales) 187 self.city = geoip2.records.City(locales, **raw_response.get("city", {})) 188 self.location = geoip2.records.Location(**raw_response.get("location", {})) 189 self.postal = geoip2.records.Postal(**raw_response.get("postal", {})) 190 self.subdivisions = geoip2.records.Subdivisions( 191 locales, *raw_response.get("subdivisions", []) 192 ) 193 194 195class Insights(City): 196 """Model for the GeoIP2 Precision: Insights web service endpoint. 197 198 .. attribute:: city 199 200 City object for the requested IP address. 201 202 :type: :py:class:`geoip2.records.City` 203 204 .. attribute:: continent 205 206 Continent object for the requested IP address. 207 208 :type: :py:class:`geoip2.records.Continent` 209 210 .. attribute:: country 211 212 Country object for the requested IP address. This record represents the 213 country where MaxMind believes the IP is located. 214 215 :type: :py:class:`geoip2.records.Country` 216 217 .. attribute:: location 218 219 Location object for the requested IP address. 220 221 .. attribute:: maxmind 222 223 Information related to your MaxMind account. 224 225 :type: :py:class:`geoip2.records.MaxMind` 226 227 .. attribute:: registered_country 228 229 The registered country object for the requested IP address. This record 230 represents the country where the ISP has registered a given IP block in 231 and may differ from the user's country. 232 233 :type: :py:class:`geoip2.records.Country` 234 235 .. attribute:: represented_country 236 237 Object for the country represented by the users of the IP address 238 when that country is different than the country in ``country``. For 239 instance, the country represented by an overseas military base. 240 241 :type: :py:class:`geoip2.records.RepresentedCountry` 242 243 .. attribute:: subdivisions 244 245 Object (tuple) representing the subdivisions of the country to which 246 the location of the requested IP address belongs. 247 248 :type: :py:class:`geoip2.records.Subdivisions` 249 250 .. attribute:: traits 251 252 Object with the traits of the requested IP address. 253 254 :type: :py:class:`geoip2.records.Traits` 255 256 """ 257 258 259class Enterprise(City): 260 """Model for the GeoIP2 Enterprise database. 261 262 .. attribute:: city 263 264 City object for the requested IP address. 265 266 :type: :py:class:`geoip2.records.City` 267 268 .. attribute:: continent 269 270 Continent object for the requested IP address. 271 272 :type: :py:class:`geoip2.records.Continent` 273 274 .. attribute:: country 275 276 Country object for the requested IP address. This record represents the 277 country where MaxMind believes the IP is located. 278 279 :type: :py:class:`geoip2.records.Country` 280 281 .. attribute:: location 282 283 Location object for the requested IP address. 284 285 .. attribute:: maxmind 286 287 Information related to your MaxMind account. 288 289 :type: :py:class:`geoip2.records.MaxMind` 290 291 .. attribute:: registered_country 292 293 The registered country object for the requested IP address. This record 294 represents the country where the ISP has registered a given IP block in 295 and may differ from the user's country. 296 297 :type: :py:class:`geoip2.records.Country` 298 299 .. attribute:: represented_country 300 301 Object for the country represented by the users of the IP address 302 when that country is different than the country in ``country``. For 303 instance, the country represented by an overseas military base. 304 305 :type: :py:class:`geoip2.records.RepresentedCountry` 306 307 .. attribute:: subdivisions 308 309 Object (tuple) representing the subdivisions of the country to which 310 the location of the requested IP address belongs. 311 312 :type: :py:class:`geoip2.records.Subdivisions` 313 314 .. attribute:: traits 315 316 Object with the traits of the requested IP address. 317 318 :type: :py:class:`geoip2.records.Traits` 319 320 """ 321 322 323class SimpleModel(SimpleEquality, metaclass=ABCMeta): 324 """Provides basic methods for non-location models""" 325 326 raw: Dict[str, Union[bool, str, int]] 327 ip_address: str 328 329 def __init__(self, raw: Dict[str, Union[bool, str, int]]) -> None: 330 self.raw = raw 331 self._network = None 332 self._prefix_len = raw.get("prefix_len") 333 self.ip_address = cast(str, raw.get("ip_address")) 334 335 def __repr__(self) -> str: 336 return f"{self.__module__}.{self.__class__.__name__}({self.raw})" 337 338 @property 339 def network(self) -> Optional[Union[ipaddress.IPv4Network, ipaddress.IPv6Network]]: 340 """The network for the record""" 341 # This code is duplicated for performance reasons 342 # pylint: disable=duplicate-code 343 network = self._network 344 if isinstance(network, (ipaddress.IPv4Network, ipaddress.IPv6Network)): 345 return network 346 347 ip_address = self.ip_address 348 prefix_len = self._prefix_len 349 if ip_address is None or prefix_len is None: 350 return None 351 network = ipaddress.ip_network(f"{ip_address}/{prefix_len}", False) 352 self._network = network 353 return network 354 355 356class AnonymousIP(SimpleModel): 357 """Model class for the GeoIP2 Anonymous IP. 358 359 This class provides the following attribute: 360 361 .. attribute:: is_anonymous 362 363 This is true if the IP address belongs to any sort of anonymous network. 364 365 :type: bool 366 367 .. attribute:: is_anonymous_vpn 368 369 This is true if the IP address is registered to an anonymous VPN 370 provider. 371 372 If a VPN provider does not register subnets under names associated with 373 them, we will likely only flag their IP ranges using the 374 ``is_hosting_provider`` attribute. 375 376 :type: bool 377 378 .. attribute:: is_hosting_provider 379 380 This is true if the IP address belongs to a hosting or VPN provider 381 (see description of ``is_anonymous_vpn`` attribute). 382 383 :type: bool 384 385 .. attribute:: is_public_proxy 386 387 This is true if the IP address belongs to a public proxy. 388 389 :type: bool 390 391 .. attribute:: is_residential_proxy 392 393 This is true if the IP address is on a suspected anonymizing network 394 and belongs to a residential ISP. 395 396 :type: bool 397 398 .. attribute:: is_tor_exit_node 399 400 This is true if the IP address is a Tor exit node. 401 402 :type: bool 403 404 .. attribute:: ip_address 405 406 The IP address used in the lookup. 407 408 :type: unicode 409 410 .. attribute:: network 411 412 The network associated with the record. In particular, this is the 413 largest network where all of the fields besides ip_address have the same 414 value. 415 416 :type: ipaddress.IPv4Network or ipaddress.IPv6Network 417 """ 418 419 is_anonymous: bool 420 is_anonymous_vpn: bool 421 is_hosting_provider: bool 422 is_public_proxy: bool 423 is_residential_proxy: bool 424 is_tor_exit_node: bool 425 426 def __init__(self, raw: Dict[str, bool]) -> None: 427 super().__init__(raw) # type: ignore 428 self.is_anonymous = raw.get("is_anonymous", False) 429 self.is_anonymous_vpn = raw.get("is_anonymous_vpn", False) 430 self.is_hosting_provider = raw.get("is_hosting_provider", False) 431 self.is_public_proxy = raw.get("is_public_proxy", False) 432 self.is_residential_proxy = raw.get("is_residential_proxy", False) 433 self.is_tor_exit_node = raw.get("is_tor_exit_node", False) 434 435 436class ASN(SimpleModel): 437 """Model class for the GeoLite2 ASN. 438 439 This class provides the following attribute: 440 441 .. attribute:: autonomous_system_number 442 443 The autonomous system number associated with the IP address. 444 445 :type: int 446 447 .. attribute:: autonomous_system_organization 448 449 The organization associated with the registered autonomous system number 450 for the IP address. 451 452 :type: unicode 453 454 .. attribute:: ip_address 455 456 The IP address used in the lookup. 457 458 :type: unicode 459 460 .. attribute:: network 461 462 The network associated with the record. In particular, this is the 463 largest network where all of the fields besides ip_address have the same 464 value. 465 466 :type: ipaddress.IPv4Network or ipaddress.IPv6Network 467 """ 468 469 autonomous_system_number: Optional[int] 470 autonomous_system_organization: Optional[str] 471 472 # pylint:disable=too-many-arguments 473 def __init__(self, raw: Dict[str, Union[str, int]]) -> None: 474 super().__init__(raw) 475 self.autonomous_system_number = cast( 476 Optional[int], raw.get("autonomous_system_number") 477 ) 478 self.autonomous_system_organization = cast( 479 Optional[str], raw.get("autonomous_system_organization") 480 ) 481 482 483class ConnectionType(SimpleModel): 484 """Model class for the GeoIP2 Connection-Type. 485 486 This class provides the following attribute: 487 488 .. attribute:: connection_type 489 490 The connection type may take the following values: 491 492 - Dialup 493 - Cable/DSL 494 - Corporate 495 - Cellular 496 497 Additional values may be added in the future. 498 499 :type: unicode 500 501 .. attribute:: ip_address 502 503 The IP address used in the lookup. 504 505 :type: unicode 506 507 .. attribute:: network 508 509 The network associated with the record. In particular, this is the 510 largest network where all of the fields besides ip_address have the same 511 value. 512 513 :type: ipaddress.IPv4Network or ipaddress.IPv6Network 514 """ 515 516 connection_type: Optional[str] 517 518 def __init__(self, raw: Dict[str, Union[str, int]]) -> None: 519 super().__init__(raw) 520 self.connection_type = cast(Optional[str], raw.get("connection_type")) 521 522 523class Domain(SimpleModel): 524 """Model class for the GeoIP2 Domain. 525 526 This class provides the following attribute: 527 528 .. attribute:: domain 529 530 The domain associated with the IP address. 531 532 :type: unicode 533 534 .. attribute:: ip_address 535 536 The IP address used in the lookup. 537 538 :type: unicode 539 540 .. attribute:: network 541 542 The network associated with the record. In particular, this is the 543 largest network where all of the fields besides ip_address have the same 544 value. 545 546 :type: ipaddress.IPv4Network or ipaddress.IPv6Network 547 548 """ 549 550 domain: Optional[str] 551 552 def __init__(self, raw: Dict[str, Union[str, int]]) -> None: 553 super().__init__(raw) 554 self.domain = cast(Optional[str], raw.get("domain")) 555 556 557class ISP(ASN): 558 """Model class for the GeoIP2 ISP. 559 560 This class provides the following attribute: 561 562 .. attribute:: autonomous_system_number 563 564 The autonomous system number associated with the IP address. 565 566 :type: int 567 568 .. attribute:: autonomous_system_organization 569 570 The organization associated with the registered autonomous system number 571 for the IP address. 572 573 :type: unicode 574 575 .. attribute:: isp 576 577 The name of the ISP associated with the IP address. 578 579 :type: unicode 580 581 .. attribute:: organization 582 583 The name of the organization associated with the IP address. 584 585 :type: unicode 586 587 .. attribute:: ip_address 588 589 The IP address used in the lookup. 590 591 :type: unicode 592 593 .. attribute:: network 594 595 The network associated with the record. In particular, this is the 596 largest network where all of the fields besides ip_address have the same 597 value. 598 599 :type: ipaddress.IPv4Network or ipaddress.IPv6Network 600 """ 601 602 isp: Optional[str] 603 organization: Optional[str] 604 605 # pylint:disable=too-many-arguments 606 def __init__(self, raw: Dict[str, Union[str, int]]) -> None: 607 super().__init__(raw) 608 self.isp = cast(Optional[str], raw.get("isp")) 609 self.organization = cast(Optional[str], raw.get("organization")) 610