├── .gitignore ├── .readthedocs.yaml ├── AUTHORS ├── ChangeLog ├── IP2Location ├── __init__.py ├── country.py ├── database.py ├── iptools.py ├── region.py └── webservice.py ├── LICENSE.TXT ├── PKG-INFO ├── README.md ├── data ├── IP-COUNTRY.BIN ├── IP2LOCATION-LITE-DB1.BIN ├── IP2LOCATION-LITE-DB1.IPV6.BIN ├── IPV6-COUNTRY.BIN ├── country_test_ipv4_data.txt └── country_test_ipv6_data.txt ├── docs ├── Makefile ├── make.bat ├── requirements.txt └── source │ ├── code.md │ ├── conf.py │ ├── googlead5f0f82eb100b8b.html │ ├── images │ ├── favicon.ico │ └── ipl-logo-square-1200.png │ ├── index.md │ └── quickstart.md ├── lookup.py ├── sample.py ├── setup.py ├── test.py └── tests ├── test_country.py ├── test_database.py ├── test_iptools.py ├── test_region.py └── test_webservice.py /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vscode/ 3 | .venv*/ 4 | venv*/ 5 | __pycache__/ 6 | dist/ 7 | .coverage* 8 | htmlcov/ 9 | .tox/ 10 | docs/_build/ 11 | *.egg-info -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # .readthedocs.yaml 2 | # Read the Docs configuration file 3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 4 | 5 | # Required 6 | version: 2 7 | 8 | # Set the OS, Python version and other tools you might need 9 | build: 10 | os: ubuntu-22.04 11 | tools: 12 | python: "3.11" 13 | # You can also specify other tool versions: 14 | # nodejs: "19" 15 | # rust: "1.64" 16 | # golang: "1.19" 17 | 18 | # Build documentation in the "docs/" directory with Sphinx 19 | sphinx: 20 | configuration: docs/source/conf.py 21 | 22 | # Optionally build your docs in additional formats such as PDF and ePub 23 | # formats: 24 | # - pdf 25 | # - epub 26 | 27 | # Optional but recommended, declare the Python requirements required 28 | # to build your documentation 29 | # See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html 30 | python: 31 | install: 32 | - requirements: docs/requirements.txt -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | K.L. Liew 2 | 3 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | 8.10.5 2025-02-21 2 | * Tested with Python 3.13. 3 | 4 | 8.10.4 2024-10-04 5 | * Tested with CPython and PyPy. 6 | 7 | 8.10.3 2024-09-27 8 | * Tested with Python 3.12. 9 | 10 | 8.10.0 2023-04-19 11 | * Added support for district, ASN and AS. 12 | 13 | 8.9.0 2022-10-14 14 | * Added Country and Region class. 15 | 16 | 8.8.1 2022-08-12 17 | * Updated the homepage link. 18 | 19 | 8.8.0 2022-06-22 20 | * Reduced file I/O. 21 | 22 | 8.7.4 2022-05-12 23 | * Fixed GitHub issue #20. 24 | 25 | 8.7.3 2022-04-15 26 | * Added test cases for IP2LocationIPTools class. 27 | 28 | 8.7.2 2022-03-21 29 | * Fixed GitHub issue #19. 30 | 31 | 8.7.1 2022-03-17 32 | * Updated readme.md. 33 | 34 | 8.7.0 2022-03-16 35 | * Added iptools class and the related tests. 36 | 37 | 8.6.4 2021-11-09 38 | * Removed debug line. 39 | 40 | 8.6.3 2021-11-08 41 | * Minor fix 42 | 43 | 8.6.2 2021-07-06 44 | * Minor fix 45 | 46 | 8.6.1 2021-07-06 47 | * Minor fix 48 | 49 | 8.6.0 2021-06-03 50 | * Support IP2Location DB25. 51 | * New function get_address_type(). 52 | * New function get_category(). 53 | 54 | 8.5.1 2020-10-21 55 | * Support SSL option in Web Service calling. 56 | 57 | 8.5.0 2020-10-21 58 | * Support IP2Location Web Service. 59 | 60 | 8.4.1 2019-10-04 61 | * Reduce file I/O to improve query performance. 62 | 63 | 8.4.0 2019-10-04 64 | * Optimized the library performance. 65 | 66 | 8.3.0 2019-08-05 67 | * Added a script to provide IP address lookup directly in shell commandline. 68 | * New mode to load and open database BIN file. 69 | 70 | 8.2.0 2019-08-05 71 | * Added fixes for returned results format. 72 | 73 | 8.1.0 2019-07-03 74 | * Added support for 6to4 and Teredo. 75 | 76 | 8.0.0 2016-07-11 77 | * Support indexed BIN files 78 | 79 | 7.0.4 2016-01-27 80 | * Bumped up to be synced with pypi version 81 | 82 | 7.0.1 2016-01-22 83 | * IP2Location object can be closed and can be used as Context Manager (vstoykov) 84 | 85 | 7.0.0 2014-08-07 86 | * Support IPv6 records 87 | 88 | 6.0.0 2013-05-23 89 | * Ported into pure python. 90 | * Remove IP2Location.c library. 91 | 92 | 5.0.0 2013-04-16 93 | * Support IP2Location DB21 - DB24 94 | * New function get_elevation() 95 | * New function get_usage_type() 96 | 97 | 4.0.0 2010-08-12 98 | * Support IP2Location DB19 - DB20 99 | * New function get_mcc() 100 | * New function get_mnc() 101 | * New function get_mobile_brand() 102 | 103 | 3.0.0 2008-08-13 104 | * Support IP2Location DB1 - DB14 105 | * New function get_idd_code() 106 | * New function get_area_code() 107 | * New function get_weather_code() 108 | * New function get_weather_name() 109 | 110 | 2.1.1 2006-11-17 111 | * Initial release 112 | * Support IP2Location IPv6 113 | * Support IP2Location DB1 - DB14 114 | * New function open() 115 | * New function get_country_short() 116 | * New function get_country_long() 117 | * New function get_region() 118 | * New function get_city() 119 | * New function get_isp() 120 | * New function get_latitude() 121 | * New function get_longitude() 122 | * New function get_domain() 123 | * New function get_zipcode() 124 | * New function get_timezone() 125 | * New function get_netspeed() 126 | * New function get_all() 127 | -------------------------------------------------------------------------------- /IP2Location/__init__.py: -------------------------------------------------------------------------------- 1 | from IP2Location.database import IP2Location 2 | from IP2Location.webservice import IP2LocationWebService 3 | from IP2Location.iptools import IP2LocationIPTools 4 | from IP2Location.country import Country 5 | from IP2Location.region import Region -------------------------------------------------------------------------------- /IP2Location/country.py: -------------------------------------------------------------------------------- 1 | import csv 2 | import os 3 | 4 | """Country class.""" 5 | class Country(object): 6 | 7 | def __init__(self, filename=None): 8 | self.fields = [] 9 | self.records = {} 10 | 11 | if filename is not None: 12 | if os.path.isfile(filename) == False: 13 | raise ValueError("The CSV file " + filename + " is not found.") 14 | 15 | if filename: 16 | line = 1 17 | with open(filename, "r", encoding = "utf-8") as f: 18 | mycsv = csv.reader(f) 19 | for row in mycsv: 20 | if type(row) == list : 21 | if (line == 1) : 22 | if row[0] != "country_code": 23 | raise ValueError("Invalid country information CSV file.") 24 | self.fields = row 25 | else: 26 | self.records[row[0]] = row 27 | line = line + 1 28 | 29 | def get_country_info(self, country_code=None): 30 | """Get the country information.""" 31 | results = [] 32 | is_not_empty = (self.records and True) or False 33 | if (is_not_empty == False): 34 | raise ValueError("No record available.") 35 | if (country_code): 36 | results = {} 37 | if country_code in self.records: 38 | for i in range(0,len(self.fields)): 39 | results[self.fields[i]] = self.records[country_code][i] 40 | return results 41 | else: 42 | return {} 43 | 44 | for key in self.records.keys(): 45 | # print (key) 46 | data = {} 47 | for i in range(0,len(self.fields)): 48 | data[self.fields[i]] = self.records[key][i] 49 | results.append(data) 50 | return results -------------------------------------------------------------------------------- /IP2Location/database.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import struct 3 | import socket 4 | import re 5 | import json 6 | import os 7 | import ipaddress 8 | import binascii 9 | from re import match 10 | 11 | MAX_IPV4_RANGE = 4294967295 12 | MAX_IPV6_RANGE = 340282366920938463463374607431768211455 13 | 14 | _COUNTRY_POSITION = (0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2) 15 | _REGION_POSITION = (0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3) 16 | _CITY_POSITION = (0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4) 17 | _LATITUDE_POSITION = (0, 0, 0, 0, 0, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5) 18 | _LONGITUDE_POSITION = (0, 0, 0, 0, 0, 6, 6, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6) 19 | _ZIPCODE_POSITION = (0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 0, 7, 7, 7, 0, 7, 0, 7, 7, 7, 0, 7, 7, 7) 20 | _TIMEZONE_POSITION = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 7, 8, 8, 8, 7, 8, 0, 8, 8, 8, 0, 8, 8, 8) 21 | _ISP_POSITION = (0, 0, 3, 0, 5, 0, 7, 5, 7, 0, 8, 0, 9, 0, 9, 0, 9, 0, 9, 7, 9, 0, 9, 7, 9, 9, 9) 22 | _DOMAIN_POSITION = (0, 0, 0, 0, 0, 0, 0, 6, 8, 0, 9, 0, 10, 0, 10, 0, 10, 0, 10, 8, 10, 0, 10, 8, 10, 10, 10) 23 | _NETSPEED_POSITION = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 11,0, 11,8, 11, 0, 11, 0, 11, 0, 11, 11, 11) 24 | _IDDCODE_POSITION = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 12, 0, 12, 0, 12, 9, 12, 0, 12, 12, 12) 25 | _AREACODE_POSITION = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10 ,13 ,0, 13, 0, 13, 10, 13, 0, 13, 13, 13) 26 | _WEATHERSTATIONCODE_POSITION = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 14, 0, 14, 0, 14, 0, 14, 14, 14) 27 | _WEATHERSTATIONNAME_POSITION = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 15, 0, 15, 0, 15, 0, 15, 15, 15) 28 | _MCC_POSITION = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 16, 0, 16, 9, 16, 16, 16) 29 | _MNC_POSITION = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 17, 0, 17, 10, 17, 17, 17) 30 | _MOBILEBRAND_POSITION = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 18, 0, 18, 11, 18, 18, 18) 31 | _ELEVATION_POSITION = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 19, 0, 19, 19, 19) 32 | _USAGETYPE_POSITION = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 20, 20, 20) 33 | _ADDRESSTYPE_POSITION = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21) 34 | _CATEGORY_POSITION = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 22) 35 | _DISTRICT_POSITION = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23) 36 | _ASN_POSITION = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24) 37 | _AS_POSITION = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25) 38 | 39 | if sys.version < '3': 40 | import urllib, httplib 41 | def urlencode(x): 42 | return urllib.urlencode(x) 43 | def httprequest(x, usessl): 44 | try: 45 | # conn = httplib.HTTPConnection("api.ip2location.com") 46 | if (usessl is True): 47 | conn = httplib.HTTPSConnection("api.ip2location.com") 48 | else: 49 | conn = httplib.HTTPConnection("api.ip2location.com") 50 | conn.request("GET", "/v2/?" + x) 51 | res = conn.getresponse() 52 | return json.loads(res.read()) 53 | except: 54 | return None 55 | def u(x): 56 | return x.decode('utf-8') 57 | def b(x): 58 | return str(x) 59 | else: 60 | import urllib.parse, http.client 61 | def urlencode(x): 62 | return urllib.parse.urlencode(x) 63 | def httprequest(x, usessl): 64 | try: 65 | # conn = http.client.HTTPConnection("api.ip2location.com") 66 | if (usessl is True): 67 | conn = http.client.HTTPSConnection("api.ip2location.com") 68 | else: 69 | conn = http.client.HTTPConnection("api.ip2location.com") 70 | conn.request("GET", "/v2/?" + x) 71 | res = conn.getresponse() 72 | return json.loads(res.read()) 73 | except: 74 | return None 75 | def u(x): 76 | if isinstance(x, bytes): 77 | return x.decode() 78 | return x 79 | def b(x): 80 | if isinstance(x, bytes): 81 | return x 82 | return x.encode('ascii') 83 | 84 | # Windows version of Python does not provide it 85 | # for compatibility with older versions of Windows. 86 | if not hasattr(socket, 'inet_pton'): 87 | def inet_pton(t, addr): 88 | import ctypes 89 | a = ctypes.WinDLL('ws2_32.dll') 90 | in_addr_p = ctypes.create_string_buffer(b(addr)) 91 | if t == socket.AF_INET: 92 | out_addr_p = ctypes.create_string_buffer(4) 93 | elif t == socket.AF_INET6: 94 | out_addr_p = ctypes.create_string_buffer(16) 95 | n = a.inet_pton(t, in_addr_p, out_addr_p) 96 | if n == 0: 97 | raise ValueError('Invalid address') 98 | return out_addr_p.raw 99 | socket.inet_pton = inet_pton 100 | 101 | def is_ipv4(ip): 102 | if '.' in ip: 103 | ip_parts = ip.split('.') 104 | if len(ip_parts) == 4: 105 | for i in range(0,len(ip_parts)): 106 | if str(ip_parts[i]).isdigit(): 107 | if int(ip_parts[i]) > 255: 108 | return False 109 | else: 110 | return False 111 | pattern = r'^([0-9]{1,3}[.]){3}[0-9]{1,3}$' 112 | if match(pattern, ip) is not None: 113 | return 4 114 | else: 115 | return False 116 | else: 117 | return False 118 | return False 119 | 120 | def is_ipv6(hostname): 121 | if ':' in hostname: 122 | return 6 123 | return False 124 | 125 | def is_valid_ip(hostname): 126 | if is_ipv4(hostname) is not False or is_ipv6(hostname) is not False: 127 | return True 128 | else: 129 | return False 130 | 131 | class IP2LocationRecord: 132 | ''' IP2Location record with all fields from the database ''' 133 | ip = None 134 | country_short = None 135 | country_long = None 136 | region = "This parameter is unavailable in selected .BIN data file. Please upgrade data file." 137 | city = "This parameter is unavailable in selected .BIN data file. Please upgrade data file." 138 | isp = "This parameter is unavailable in selected .BIN data file. Please upgrade data file." 139 | latitude = "This parameter is unavailable in selected .BIN data file. Please upgrade data file." 140 | longitude = "This parameter is unavailable in selected .BIN data file. Please upgrade data file." 141 | domain = "This parameter is unavailable in selected .BIN data file. Please upgrade data file." 142 | zipcode = "This parameter is unavailable in selected .BIN data file. Please upgrade data file." 143 | timezone = "This parameter is unavailable in selected .BIN data file. Please upgrade data file." 144 | netspeed = "This parameter is unavailable in selected .BIN data file. Please upgrade data file." 145 | idd_code = "This parameter is unavailable in selected .BIN data file. Please upgrade data file." 146 | area_code = "This parameter is unavailable in selected .BIN data file. Please upgrade data file." 147 | weather_code = "This parameter is unavailable in selected .BIN data file. Please upgrade data file." 148 | weather_name = "This parameter is unavailable in selected .BIN data file. Please upgrade data file." 149 | mcc = "This parameter is unavailable in selected .BIN data file. Please upgrade data file." 150 | mnc = "This parameter is unavailable in selected .BIN data file. Please upgrade data file." 151 | mobile_brand = "This parameter is unavailable in selected .BIN data file. Please upgrade data file." 152 | elevation = "This parameter is unavailable in selected .BIN data file. Please upgrade data file." 153 | usage_type = "This parameter is unavailable in selected .BIN data file. Please upgrade data file." 154 | address_type = "This parameter is unavailable in selected .BIN data file. Please upgrade data file." 155 | category = "This parameter is unavailable in selected .BIN data file. Please upgrade data file." 156 | district = "This parameter is unavailable in selected .BIN data file. Please upgrade data file." 157 | asn = "This parameter is unavailable in selected .BIN data file. Please upgrade data file." 158 | as_name = "This parameter is unavailable in selected .BIN data file. Please upgrade data file." 159 | 160 | def __str__(self): 161 | return str(self.__dict__) 162 | 163 | def __repr__(self): 164 | return repr(self.__dict__) 165 | 166 | class IP2Location(object): 167 | ''' IP2Location database ''' 168 | 169 | def __init__(self, filename=None,mode='FILE_IO'): 170 | ''' Creates a database object and opens a file if filename is given 171 | 172 | ''' 173 | self.mode = mode 174 | 175 | if filename is not None: 176 | if os.path.isfile(filename) == False: 177 | raise ValueError("The database file does not seem to exist.") 178 | 179 | if filename: 180 | self.open(filename) 181 | 182 | def __enter__(self): 183 | if not hasattr(self, '_f') or self._f.closed: 184 | raise ValueError("Cannot enter context with closed file") 185 | return self 186 | 187 | def __exit__(self, exc_type, exc_value, traceback): 188 | self.close() 189 | 190 | def open(self, filename): 191 | ''' Opens a database file ''' 192 | # Ensure old file is closed before opening a new one 193 | self.close() 194 | 195 | if (self.mode == 'SHARED_MEMORY'): 196 | import mmap 197 | db1 = open(filename, 'r+b') 198 | self._f = mmap.mmap(db1.fileno(), 0) 199 | db1.close() 200 | del db1 201 | elif (self.mode == 'FILE_IO'): 202 | self._f = open(filename, 'rb') 203 | else: 204 | raise ValueError("Invalid mode. Please enter either FILE_IO or SHARED_MEMORY.") 205 | if (self.mode == 'SHARED_MEMORY'): 206 | # We can directly use slice notation to read content from mmap object. https://docs.python.org/3/library/mmap.html?highlight=mmap#module-mmap 207 | header_row = self._f[0:32] 208 | else: 209 | self._f.seek(0) 210 | header_row = self._f.read(32) 211 | self._dbtype = struct.unpack('B', header_row[0:1])[0] 212 | self._dbcolumn = struct.unpack('B', header_row[1:2])[0] 213 | self._dbyear = struct.unpack('B', header_row[2:3])[0] 214 | self._dbmonth = struct.unpack('B', header_row[3:4])[0] 215 | self._dbday = struct.unpack('B', header_row[4:5])[0] 216 | self._ipv4dbcount = struct.unpack(' 20 and self._productcode != 0) : 227 | self._f.close() 228 | del self._f 229 | raise ValueError("Incorrect IP2Location BIN file format. Please make sure that you are using the latest IP2Location BIN file.") 230 | 231 | 232 | def close(self): 233 | if hasattr(self, '_f'): 234 | # If there is file close it. 235 | self._f.close() 236 | del self._f 237 | 238 | def get_country_short(self, ip): 239 | ''' Get country_short ''' 240 | rec = self.get_all(ip) 241 | return rec and rec.country_short 242 | def get_country_long(self, ip): 243 | ''' Get country_long ''' 244 | rec = self.get_all(ip) 245 | return rec and rec.country_long 246 | def get_region(self, ip): 247 | ''' Get region ''' 248 | rec = self.get_all(ip) 249 | return rec and rec.region 250 | def get_city(self, ip): 251 | ''' Get city ''' 252 | rec = self.get_all(ip) 253 | return rec and rec.city 254 | def get_isp(self, ip): 255 | ''' Get isp ''' 256 | rec = self.get_all(ip) 257 | return rec and rec.isp 258 | def get_latitude(self, ip): 259 | ''' Get latitude ''' 260 | rec = self.get_all(ip) 261 | return rec and rec.latitude 262 | def get_longitude(self, ip): 263 | ''' Get longitude ''' 264 | rec = self.get_all(ip) 265 | return rec and rec.longitude 266 | def get_domain(self, ip): 267 | ''' Get domain ''' 268 | rec = self.get_all(ip) 269 | return rec and rec.domain 270 | def get_zipcode(self, ip): 271 | ''' Get zipcode ''' 272 | rec = self.get_all(ip) 273 | return rec and rec.zipcode 274 | def get_timezone(self, ip): 275 | ''' Get timezone ''' 276 | rec = self.get_all(ip) 277 | return rec and rec.timezone 278 | def get_netspeed(self, ip): 279 | ''' Get netspeed ''' 280 | rec = self.get_all(ip) 281 | return rec and rec.netspeed 282 | def get_idd_code(self, ip): 283 | ''' Get idd_code ''' 284 | rec = self.get_all(ip) 285 | return rec and rec.idd_code 286 | def get_area_code(self, ip): 287 | ''' Get area_code ''' 288 | rec = self.get_all(ip) 289 | return rec and rec.area_code 290 | def get_weather_code(self, ip): 291 | ''' Get weather_code ''' 292 | rec = self.get_all(ip) 293 | return rec and rec.weather_code 294 | def get_weather_name(self, ip): 295 | ''' Get weather_name ''' 296 | rec = self.get_all(ip) 297 | return rec and rec.weather_name 298 | def get_mcc(self, ip): 299 | ''' Get mcc ''' 300 | rec = self.get_all(ip) 301 | return rec and rec.mcc 302 | def get_mnc(self, ip): 303 | ''' Get mnc ''' 304 | rec = self.get_all(ip) 305 | return rec and rec.mnc 306 | def get_mobile_brand(self, ip): 307 | ''' Get mobile_brand ''' 308 | rec = self.get_all(ip) 309 | return rec and rec.mobile_brand 310 | def get_elevation(self, ip): 311 | ''' Get elevation ''' 312 | rec = self.get_all(ip) 313 | return rec and rec.elevation 314 | def get_usage_type(self, ip): 315 | ''' Get usage_type ''' 316 | rec = self.get_all(ip) 317 | return rec and rec.usage_type 318 | def get_address_type(self, ip): 319 | ''' Get address_type ''' 320 | rec = self.get_all(ip) 321 | return rec and rec.address_type 322 | def get_category(self, ip): 323 | ''' Get category ''' 324 | rec = self.get_all(ip) 325 | return rec and rec.category 326 | def get_district(self, ip): 327 | ''' Get district ''' 328 | rec = self.get_all(ip) 329 | return rec and rec.district 330 | def get_asn(self, ip): 331 | ''' Get asn ''' 332 | rec = self.get_all(ip) 333 | return rec and rec.asn 334 | def get_as(self, ip): 335 | ''' Get as_name ''' 336 | rec = self.get_all(ip) 337 | return rec and rec.as_name 338 | 339 | def get_all(self, addr): 340 | ''' Get the whole record with all fields read from the file 341 | 342 | Arguments: 343 | 344 | addr: IPv4 or IPv6 address as a string 345 | 346 | Returns IP2LocationRecord or None if address not found in file 347 | ''' 348 | return self._get_record(addr) 349 | 350 | def find(self, addr): 351 | ''' Get the whole record with all fields read from the file 352 | 353 | Arguments: 354 | 355 | addr: IPv4 or IPv6 address as a string 356 | 357 | Returns IP2LocationRecord or None if address not found in file 358 | 359 | This function will be obselete in future. 360 | ''' 361 | return self._get_record(addr) 362 | 363 | def _reads(self, offset): 364 | self._f.seek(offset - 1) 365 | '''''' 366 | data = self._f.read(257) 367 | char_count = struct.unpack('B', data[0:1])[0] 368 | string = data[1:char_count+1] 369 | if sys.version < '3': 370 | return str(string.decode('iso-8859-1').encode('utf-8')) 371 | else : 372 | return u(string.decode('iso-8859-1').encode('utf-8')) 373 | 374 | def _readi(self, offset): 375 | self._f.seek(offset - 1) 376 | # return struct.unpack('= 281470681743360) and (ipnum <= 281474976710655)): 559 | ipv = 4 560 | ipnum = ipnum - 281470681743360 561 | else: 562 | ipv = 6 563 | else: 564 | #reformat 6to4 address to ipv4 address 2002:: to 2002:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF 565 | if ((ipnum >= 42545680458834377588178886921629466624) and (ipnum <= 42550872755692912415807417417958686719)): 566 | ipv = 4 567 | ipnum = ipnum >> 80 568 | ipnum = ipnum % 4294967296 569 | #reformat Teredo address to ipv4 address 2001:0000:: to 2001:0000:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF: 570 | elif ((ipnum >= 42540488161975842760550356425300246528) and (ipnum <= 42540488241204005274814694018844196863)): 571 | ipv = 4 572 | ipnum = ~ ipnum 573 | ipnum = ipnum % 4294967296 574 | else: 575 | ipv = 6 576 | ''' 577 | #reformat 6to4 address to ipv4 address 2002:: to 2002:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF 578 | if ((ipnum >= 42545680458834377588178886921629466624) and (ipnum <= 42550872755692912415807417417958686719)): 579 | ipv = 4 580 | ipnum = ipnum >> 80 581 | ipnum = ipnum % 4294967296 582 | #reformat Teredo address to ipv4 address 2001:0000:: to 2001:0000:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF: 583 | elif ((ipnum >= 42540488161975842760550356425300246528) and (ipnum <= 42540488241204005274814694018844196863)): 584 | ipv = 4 585 | ipnum = ~ ipnum 586 | ipnum = ipnum % 4294967296 587 | # reformat ipv4 address in ipv6 588 | elif ((ipnum >= 281470681743360) and (ipnum <= 281474976710655)): 589 | ipv = 4 590 | ipnum = ipnum - 281470681743360 591 | else: 592 | ipv = 6 593 | except (socket.error, OSError, ValueError): 594 | ipv = 0 595 | ipnum = -1 596 | elif is_ipv4(addr) == 4 and '256' not in addr: 597 | try: 598 | # ipnum = int(ipaddress.IPv4Address(addr)) 599 | ipnum = struct.unpack('!L', socket.inet_pton(socket.AF_INET, addr))[0] 600 | ipv = 4 601 | except (socket.error, OSError, ValueError): 602 | ipv = 0 603 | ipnum = -1 604 | return ipv, ipnum 605 | 606 | def _get_record(self, ip): 607 | self.original_ip = ip 608 | low = 0 609 | ipv, ipnum = self._parse_addr(ip) 610 | if ipv == 0: 611 | rec = IP2LocationRecord() 612 | rec.country_short = "INVALID IP ADDRESS" 613 | rec.country_long = "INVALID IP ADDRESS" 614 | rec.region = "INVALID IP ADDRESS" 615 | rec.city = "INVALID IP ADDRESS" 616 | rec.isp = "INVALID IP ADDRESS" 617 | rec.latitude = "INVALID IP ADDRESS" 618 | rec.longitude = "INVALID IP ADDRESS" 619 | rec.domain = "INVALID IP ADDRESS" 620 | rec.zipcode = "INVALID IP ADDRESS" 621 | rec.timezone = "INVALID IP ADDRESS" 622 | rec.netspeed = "INVALID IP ADDRESS" 623 | rec.idd_code = "INVALID IP ADDRESS" 624 | rec.area_code = "INVALID IP ADDRESS" 625 | rec.weather_code = "INVALID IP ADDRESS" 626 | rec.weather_name = "INVALID IP ADDRESS" 627 | rec.mcc = "INVALID IP ADDRESS" 628 | rec.mnc = "INVALID IP ADDRESS" 629 | rec.mobile_brand = "INVALID IP ADDRESS" 630 | rec.elevation = "INVALID IP ADDRESS" 631 | rec.usage_type = "INVALID IP ADDRESS" 632 | rec.address_type = "INVALID IP ADDRESS" 633 | rec.category = "INVALID IP ADDRESS" 634 | rec.district = "INVALID IP ADDRESS" 635 | rec.asn = "INVALID IP ADDRESS" 636 | rec.as_name = "INVALID IP ADDRESS" 637 | return rec 638 | else: 639 | if ipv == 4: 640 | # ipno = struct.unpack('!L', socket.inet_pton(socket.AF_INET, ip))[0] 641 | if (ipnum == MAX_IPV4_RANGE): 642 | ipno = ipnum - 1 643 | else: 644 | ipno = ipnum 645 | off = 0 646 | baseaddr = self._ipv4dbaddr 647 | high = self._ipv4dbcount 648 | if self._ipv4indexbaseaddr > 0: 649 | indexpos = ((ipno >> 16) << 3) + self._ipv4indexbaseaddr 650 | # low = self._readi(indexpos) 651 | # high = self._readi(indexpos + 4) 652 | low,high = self.read32x2(indexpos) 653 | 654 | elif ipv == 6: 655 | if self._ipv6dbcount == 0: 656 | # raise ValueError('Please use IPv6 BIN file for IPv6 Address.') 657 | rec = IP2LocationRecord() 658 | rec.country_short = "IPV6 ADDRESS MISSING IN IPV4 BIN" 659 | rec.country_long = "IPV6 ADDRESS MISSING IN IPV4 BIN" 660 | rec.region = "IPV6 ADDRESS MISSING IN IPV4 BIN" 661 | rec.city = "IPV6 ADDRESS MISSING IN IPV4 BIN" 662 | rec.isp = "IPV6 ADDRESS MISSING IN IPV4 BIN" 663 | rec.latitude = "IPV6 ADDRESS MISSING IN IPV4 BIN" 664 | rec.longitude = "IPV6 ADDRESS MISSING IN IPV4 BIN" 665 | rec.domain = "IPV6 ADDRESS MISSING IN IPV4 BIN" 666 | rec.zipcode = "IPV6 ADDRESS MISSING IN IPV4 BIN" 667 | rec.timezone = "IPV6 ADDRESS MISSING IN IPV4 BIN" 668 | rec.netspeed = "IPV6 ADDRESS MISSING IN IPV4 BIN" 669 | rec.idd_code = "IPV6 ADDRESS MISSING IN IPV4 BIN" 670 | rec.area_code = "IPV6 ADDRESS MISSING IN IPV4 BIN" 671 | rec.weather_code = "IPV6 ADDRESS MISSING IN IPV4 BIN" 672 | rec.weather_name = "IPV6 ADDRESS MISSING IN IPV4 BIN" 673 | rec.mcc = "IPV6 ADDRESS MISSING IN IPV4 BIN" 674 | rec.mnc = "IPV6 ADDRESS MISSING IN IPV4 BIN" 675 | rec.mobile_brand = "IPV6 ADDRESS MISSING IN IPV4 BIN" 676 | rec.elevation = "IPV6 ADDRESS MISSING IN IPV4 BIN" 677 | rec.usage_type = "IPV6 ADDRESS MISSING IN IPV4 BIN" 678 | rec.address_type = "IPV6 ADDRESS MISSING IN IPV4 BIN" 679 | rec.category = "IPV6 ADDRESS MISSING IN IPV4 BIN" 680 | rec.district = "IPV6 ADDRESS MISSING IN IPV4 BIN" 681 | rec.asn = "IPV6 ADDRESS MISSING IN IPV4 BIN" 682 | rec.as_name = "IPV6 ADDRESS MISSING IN IPV4 BIN" 683 | return rec 684 | # a, b = struct.unpack('!QQ', socket.inet_pton(socket.AF_INET6, ip)) 685 | # ipno = (a << 64) | b 686 | if (ipnum == MAX_IPV6_RANGE): 687 | ipno = ipnum - 1 688 | else: 689 | ipno = ipnum 690 | off = 12 691 | baseaddr = self._ipv6dbaddr 692 | high = self._ipv6dbcount 693 | if self._ipv6indexbaseaddr > 0: 694 | indexpos = ((ipno >> 112) << 3) + self._ipv6indexbaseaddr 695 | low = self._readi(indexpos) 696 | high = self._readi(indexpos + 4) 697 | 698 | while low <= high: 699 | mid = int((low + high) / 2) 700 | if ipv == 4: 701 | ipfrom, ipto = self.readRow32(baseaddr + mid * self._dbcolumn * 4 ) 702 | elif ipv == 6: 703 | ipfrom, ipto = self.readRow128(baseaddr + mid * ((self._dbcolumn * 4) + 12) ) 704 | 705 | if ipfrom <= ipno < ipto: 706 | return self._read_record(mid, ipv) 707 | else: 708 | if ipno < ipfrom: 709 | high = mid - 1 710 | else: 711 | low = mid + 1 -------------------------------------------------------------------------------- /IP2Location/iptools.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import struct 3 | import socket 4 | import re 5 | import json 6 | import os 7 | import ipaddress 8 | import binascii 9 | from re import match 10 | 11 | if sys.version < '3': 12 | import urllib, httplib 13 | def urlencode(x): 14 | return urllib.urlencode(x) 15 | def httprequest(x, usessl): 16 | try: 17 | # conn = httplib.HTTPConnection("api.ip2location.com") 18 | if (usessl is True): 19 | conn = httplib.HTTPSConnection("api.ip2location.com") 20 | else: 21 | conn = httplib.HTTPConnection("api.ip2location.com") 22 | conn.request("GET", "/v2/?" + x) 23 | res = conn.getresponse() 24 | return json.loads(res.read()) 25 | except: 26 | return None 27 | def u(x): 28 | return x.decode('utf-8') 29 | def b(x): 30 | return str(x) 31 | else: 32 | import urllib.parse, http.client 33 | def urlencode(x): 34 | return urllib.parse.urlencode(x) 35 | def httprequest(x, usessl): 36 | try: 37 | # conn = http.client.HTTPConnection("api.ip2location.com") 38 | if (usessl is True): 39 | conn = http.client.HTTPSConnection("api.ip2location.com") 40 | else: 41 | conn = http.client.HTTPConnection("api.ip2location.com") 42 | conn.request("GET", "/v2/?" + x) 43 | res = conn.getresponse() 44 | return json.loads(res.read()) 45 | except: 46 | return None 47 | def u(x): 48 | if isinstance(x, bytes): 49 | return x.decode() 50 | return x 51 | def b(x): 52 | if isinstance(x, bytes): 53 | return x 54 | return x.encode('ascii') 55 | 56 | # Windows version of Python does not provide it 57 | # for compatibility with older versions of Windows. 58 | if not hasattr(socket, 'inet_pton'): 59 | def inet_pton(t, addr): 60 | import ctypes 61 | a = ctypes.WinDLL('ws2_32.dll') 62 | in_addr_p = ctypes.create_string_buffer(b(addr)) 63 | if t == socket.AF_INET: 64 | out_addr_p = ctypes.create_string_buffer(4) 65 | elif t == socket.AF_INET6: 66 | out_addr_p = ctypes.create_string_buffer(16) 67 | n = a.inet_pton(t, in_addr_p, out_addr_p) 68 | if n == 0: 69 | raise ValueError('Invalid address') 70 | return out_addr_p.raw 71 | socket.inet_pton = inet_pton 72 | 73 | def is_ipv4(ip): 74 | if '.' in ip: 75 | ip_parts = ip.split('.') 76 | if len(ip_parts) == 4: 77 | for i in range(0,len(ip_parts)): 78 | if str(ip_parts[i]).isdigit(): 79 | if int(ip_parts[i]) > 255: 80 | return False 81 | else: 82 | return False 83 | pattern = r'^([0-9]{1,3}[.]){3}[0-9]{1,3}$' 84 | if match(pattern, ip) is not None: 85 | return 4 86 | else: 87 | return False 88 | else: 89 | return False 90 | return False 91 | 92 | def is_ipv6(hostname): 93 | if ':' in hostname: 94 | return 6 95 | return False 96 | 97 | def is_valid_ip(hostname): 98 | if is_ipv4(hostname) is not False or is_ipv6(hostname) is not False: 99 | return True 100 | else: 101 | return False 102 | 103 | class IP2LocationIPTools(object): 104 | 105 | def is_ipv4(self, ip): 106 | if '.' in ip: 107 | ip_parts = ip.split('.') 108 | if len(ip_parts) == 4: 109 | for i in range(0,len(ip_parts)): 110 | if str(ip_parts[i]).isdigit(): 111 | if int(ip_parts[i]) > 255: 112 | return False 113 | else: 114 | return False 115 | pattern = r'^([0-9]{1,3}[.]){3}[0-9]{1,3}$' 116 | if match(pattern, ip) is not None: 117 | return True 118 | else: 119 | return False 120 | else: 121 | return False 122 | return False 123 | 124 | def is_ipv6(self, ip): 125 | try: 126 | socket.inet_pton(socket.AF_INET6, ip) 127 | except socket.error: # not a valid address 128 | return False 129 | return True 130 | 131 | def ipv4_to_decimal(self, ip): 132 | try: 133 | ipnum = struct.unpack('!L', socket.inet_pton(socket.AF_INET, ip))[0] 134 | except (socket.error, OSError, ValueError): 135 | # ipnum = -1 136 | return 137 | return ipnum 138 | 139 | def decimal_to_ipv4(self, decimal): 140 | if str(decimal).isdigit() is False: 141 | return 142 | if (int(decimal) > 4294967295): 143 | return 144 | else: 145 | return (socket.inet_ntoa(struct.pack('!I', int(decimal)))) 146 | 147 | def ipv6_to_decimal(self, ip): 148 | if self.is_ipv6(ip) is False: 149 | return 150 | return(int(ipaddress.ip_address(u(ip)))) 151 | 152 | def decimal_to_ipv6(self, decimal): 153 | if str(decimal).isdigit() is False: 154 | return 155 | result = ipaddress.IPv6Address(int(decimal)) 156 | if (result.ipv4_mapped != None): 157 | return('::ffff:' + str(result.ipv4_mapped)) 158 | else: 159 | return str(result) 160 | 161 | def ipv4_to_cidr(self, from_ip, to_ip): 162 | if self.is_ipv4(from_ip) is False: 163 | return 164 | if self.is_ipv4(to_ip) is False: 165 | return 166 | startip = ipaddress.IPv4Address(u(from_ip)) 167 | endip = ipaddress.IPv4Address(u(to_ip)) 168 | ar = [ipaddr for ipaddr in ipaddress.summarize_address_range(startip, endip)] 169 | ar1 = [] 170 | for i in range(len(ar)): 171 | ar1.append(str(ar[i])) 172 | return (ar1) 173 | 174 | def ipv6_to_cidr(self, from_ip, to_ip): 175 | if self.is_ipv6(from_ip) is False: 176 | return 177 | if self.is_ipv6(to_ip) is False: 178 | return 179 | startip = ipaddress.IPv6Address(u(from_ip)) 180 | endip = ipaddress.IPv6Address(u(to_ip)) 181 | ar = [ipaddr for ipaddr in ipaddress.summarize_address_range(startip, endip)] 182 | ar1 = [] 183 | for i in range(len(ar)): 184 | ar1.append(str(ar[i])) 185 | return (ar1) 186 | 187 | def cidr_to_ipv4(self, cidr): 188 | if '/' not in cidr: 189 | return 190 | net = ipaddress.ip_network(u(cidr)) 191 | return({"ip_start": str(net[0]), "ip_end": str(net[-1])}) 192 | 193 | def cidr_to_ipv6(self, cidr): 194 | if '/' not in cidr: 195 | return 196 | net = ipaddress.ip_network(cidr, False) 197 | # return({"ip_start": net.network_address.exploded, "ip_end": net.broadcast_address.exploded}) 198 | return({"ip_start": str(net[0]), "ip_end": str(net[-1])}) 199 | 200 | def compressed_ipv6(self, ip): 201 | if self.is_ipv6(ip) is False: 202 | return 203 | return ((ipaddress.IPv6Address(u(ip)).compressed)) 204 | 205 | def expand_ipv6(self, ip): 206 | if self.is_ipv6(ip) is False: 207 | return 208 | return ((ipaddress.IPv6Address(u(ip)).exploded)) 209 | -------------------------------------------------------------------------------- /IP2Location/region.py: -------------------------------------------------------------------------------- 1 | import csv 2 | import os 3 | 4 | """Region class.""" 5 | class Region(object): 6 | def __init__(self, filename=None): 7 | 8 | self.fields = [] 9 | self.records = {} 10 | 11 | if filename is not None: 12 | if os.path.isfile(filename) == False: 13 | raise ValueError("The CSV file " + filename + " is not found.") 14 | 15 | if filename: 16 | line = 1 17 | with open(filename, "r", encoding = "utf-8") as f: 18 | mycsv = csv.reader(f) 19 | for row in mycsv: 20 | if type(row) == list : 21 | if row[0] not in self.records.keys(): 22 | self.records[row[0]] = [] 23 | if (line == 1) : 24 | if row[1] != "subdivision_name": 25 | raise ValueError("Invalid region information CSV file.") 26 | self.fields = row 27 | else: 28 | 29 | self.records[row[0]].append({"code": row[2], 30 | "name": row[1]}) 31 | line = line + 1 32 | 33 | def get_region_code(self, country_code, region_name): 34 | """Get region code by country code and region name.""" 35 | is_not_empty = (self.records and True) or False 36 | if (is_not_empty == False): 37 | raise ValueError("No record available.") 38 | if country_code in self.records: 39 | print(self.records[country_code]) 40 | for i in range(0,len(self.records[country_code])): 41 | if (region_name.upper() == 42 | self.records[country_code][i]["name"].upper()): 43 | return self.records[country_code][i]["code"] 44 | else: 45 | return -------------------------------------------------------------------------------- /IP2Location/webservice.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import struct 3 | import socket 4 | import re 5 | import json 6 | import os 7 | import ipaddress 8 | import binascii 9 | from re import match 10 | 11 | if sys.version < '3': 12 | import urllib, httplib 13 | def urlencode(x): 14 | return urllib.urlencode(x) 15 | def httprequest(x, usessl): 16 | try: 17 | # conn = httplib.HTTPConnection("api.ip2location.com") 18 | if (usessl is True): 19 | conn = httplib.HTTPSConnection("api.ip2location.com") 20 | else: 21 | conn = httplib.HTTPConnection("api.ip2location.com") 22 | conn.request("GET", "/v2/?" + x) 23 | res = conn.getresponse() 24 | return json.loads(res.read()) 25 | except: 26 | return None 27 | def u(x): 28 | return x.decode('utf-8') 29 | def b(x): 30 | return str(x) 31 | else: 32 | import urllib.parse, http.client 33 | def urlencode(x): 34 | return urllib.parse.urlencode(x) 35 | def httprequest(x, usessl): 36 | try: 37 | # conn = http.client.HTTPConnection("api.ip2location.com") 38 | if (usessl is True): 39 | conn = http.client.HTTPSConnection("api.ip2location.com") 40 | else: 41 | conn = http.client.HTTPConnection("api.ip2location.com") 42 | conn.request("GET", "/v2/?" + x) 43 | res = conn.getresponse() 44 | return json.loads(res.read()) 45 | except: 46 | return None 47 | def u(x): 48 | if isinstance(x, bytes): 49 | return x.decode() 50 | return x 51 | def b(x): 52 | if isinstance(x, bytes): 53 | return x 54 | return x.encode('ascii') 55 | 56 | # Windows version of Python does not provide it 57 | # for compatibility with older versions of Windows. 58 | if not hasattr(socket, 'inet_pton'): 59 | def inet_pton(t, addr): 60 | import ctypes 61 | a = ctypes.WinDLL('ws2_32.dll') 62 | in_addr_p = ctypes.create_string_buffer(b(addr)) 63 | if t == socket.AF_INET: 64 | out_addr_p = ctypes.create_string_buffer(4) 65 | elif t == socket.AF_INET6: 66 | out_addr_p = ctypes.create_string_buffer(16) 67 | n = a.inet_pton(t, in_addr_p, out_addr_p) 68 | if n == 0: 69 | raise ValueError('Invalid address') 70 | return out_addr_p.raw 71 | socket.inet_pton = inet_pton 72 | 73 | def is_ipv4(ip): 74 | if '.' in ip: 75 | ip_parts = ip.split('.') 76 | if len(ip_parts) == 4: 77 | for i in range(0,len(ip_parts)): 78 | if str(ip_parts[i]).isdigit(): 79 | if int(ip_parts[i]) > 255: 80 | return False 81 | else: 82 | return False 83 | pattern = r'^([0-9]{1,3}[.]){3}[0-9]{1,3}$' 84 | if match(pattern, ip) is not None: 85 | return 4 86 | else: 87 | return False 88 | else: 89 | return False 90 | return False 91 | 92 | def is_ipv6(hostname): 93 | if ':' in hostname: 94 | return 6 95 | return False 96 | 97 | def is_valid_ip(hostname): 98 | if is_ipv4(hostname) is not False or is_ipv6(hostname) is not False: 99 | return True 100 | else: 101 | return False 102 | 103 | class IP2LocationWebService(object): 104 | ''' IP2Location web service ''' 105 | def __init__(self,apikey,package,usessl=True): 106 | if ((re.match(r"^[0-9A-Z]{10}$", apikey) == None) and (apikey != 'demo')): 107 | raise ValueError("Please provide a valid IP2Location web service API key.") 108 | if (re.match(r"^WS[0-9]+$", package) == None): 109 | package = 'WS1' 110 | self.apikey = apikey 111 | self.package = package 112 | self.usessl = usessl 113 | 114 | def lookup(self,ip,addons=[],language='en'): 115 | '''This function will look the given IP address up in IP2Location web service.''' 116 | parameters = urlencode((("key", self.apikey), ("ip", ip), ("package", self.package), ("addon", ','.join(addons)), ("lang", language))) 117 | response = httprequest(parameters, self.usessl) 118 | if (response == None): 119 | return False 120 | # if ('response' in response): 121 | if (('response' in response) and (response['response'] != 'OK')): 122 | raise IP2LocationAPIError(response['response']) 123 | return response 124 | 125 | def getcredit(self): 126 | '''Get the remaing credit in your IP2Location web service account.''' 127 | parameters = urlencode((("key", self.apikey), ("check", True))) 128 | response = httprequest(parameters, self.usessl) 129 | if (response == None): 130 | return 0 131 | if ('response' in response is False): 132 | return 0 133 | return response['response'] 134 | 135 | class IP2LocationAPIError(Exception): 136 | """Raise for IP2Location API Error Message""" -------------------------------------------------------------------------------- /LICENSE.TXT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 - 2025 IP2Location.com 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /PKG-INFO: -------------------------------------------------------------------------------- 1 | Metadata-Version: 1.0 2 | Name: IP2Location 3 | Version: 8.10.5 4 | Summary: Python API for IP2Location database 5 | Home-page: http://www.ip2location.com 6 | Author: IP2Location 7 | Author-email: support@ip2location.com 8 | License: MIT 9 | Description: Please refer to LICENSE.txt 10 | Platform: Mac OS, Linux, Windows 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # IP2Location Python Library 2 | 3 | ![PyPI](https://img.shields.io/pypi/v/IP2Location) 4 | ![PyPI - Downloads](https://img.shields.io/pypi/dm/IP2Location) 5 | ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/ip2location) 6 | 7 | This is a IP2Location Python library that enables the user to find the country, region or state, city, latitude and longitude, ZIP code, time zone, Internet Service Provider (ISP) or company name, domain name, net speed, area code, weather station code, weather station name, mobile country code (MCC), mobile network code (MNC) and carrier brand, elevation, usage type, address type and IAB category by IP address or hostname originates from. 8 | 9 | This library reads geo-location information from the **IP2Location BIN database** file and supports lookup for both IPv4 and IPv6 addresses. 10 | 11 | # Developer Documentation 12 | 13 | To learn more about installation, usage, and code examples, please visit the developer documentation at [https://ip2location-python.readthedocs.io/en/latest/index.html](https://ip2location-python.readthedocs.io/en/latest/index.html). 14 | 15 | # IP2Location BIN Databases 16 | 17 | To use this library, you must download the IP2Location BIN database. 18 | 19 | - Download Free IP2Location LITE databases at [https://lite.ip2location.com](https://lite.ip2location.com/) 20 | - Download IP2Location commercial databases at [https://www.ip2location.com](https://www.ip2location.com/developers) 21 | 22 | # IPv4 versus IPv6 BIN Database 23 | 24 | Below are general guidelines for determining whether to use the IPv4 BIN database or the IPv6 BIN database. 25 | 26 | - Use the IPv4 BIN database if you just need to query for IPv4 addresses. 27 | - Use the IPv6 BIN database if you need to query for both IPv4 and IPv6 addresses. 28 | 29 | # SDK or Library for Other Programming Languages 30 | 31 | To learn about other readily available SDKs or libraries for different programming languages, please visit [https://www.ip2location.com/development-libraries](https://www.ip2location.com/development-libraries). 32 | 33 | # Support 34 | 35 | Email: [support@ip2location.com](mailto:support@ip2location.com) 36 | 37 | URL: [https://www.ip2location.com](https://www.ip2location.com/) 38 | -------------------------------------------------------------------------------- /data/IP-COUNTRY.BIN: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrislim2888/IP2Location-Python/fcc8811a9393275c4e1aea01841f5d6c6e25e669/data/IP-COUNTRY.BIN -------------------------------------------------------------------------------- /data/IP2LOCATION-LITE-DB1.BIN: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrislim2888/IP2Location-Python/fcc8811a9393275c4e1aea01841f5d6c6e25e669/data/IP2LOCATION-LITE-DB1.BIN -------------------------------------------------------------------------------- /data/IP2LOCATION-LITE-DB1.IPV6.BIN: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrislim2888/IP2Location-Python/fcc8811a9393275c4e1aea01841f5d6c6e25e669/data/IP2LOCATION-LITE-DB1.IPV6.BIN -------------------------------------------------------------------------------- /data/IPV6-COUNTRY.BIN: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrislim2888/IP2Location-Python/fcc8811a9393275c4e1aea01841f5d6c6e25e669/data/IPV6-COUNTRY.BIN -------------------------------------------------------------------------------- /data/country_test_ipv4_data.txt: -------------------------------------------------------------------------------- 1 | 19.5.10.1 US 2 | 25.5.10.2 GB 3 | 43.5.10.3 JP 4 | 47.5.10.4 CA 5 | 51.5.10.5 GB 6 | 53.5.10.6 DE 7 | 80.5.10.7 GB 8 | 81.5.10.8 IL 9 | 83.5.10.9 PL 10 | 85.5.10.0 CH 11 | -------------------------------------------------------------------------------- /data/country_test_ipv6_data.txt: -------------------------------------------------------------------------------- 1 | 2001:0200:0102:: JP 2 | 2a01:04f8:0d16:25c2:: DE 3 | 2a01:04f8:0d16:26c2:: DE 4 | 2a01:ad20:: ES 5 | 2a01:af60:: PL 6 | 2a01:b200:: SK 7 | 2a01:b340:: IE 8 | 2a01:b4c0:: CZ 9 | 2a01:b600:8001:: IT 10 | 2a01:b6c0:: SE 11 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=build 12 | 13 | %SPHINXBUILD% >NUL 2>NUL 14 | if errorlevel 9009 ( 15 | echo. 16 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 17 | echo.installed, then set the SPHINXBUILD environment variable to point 18 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 19 | echo.may add the Sphinx directory to PATH. 20 | echo. 21 | echo.If you don't have Sphinx installed, grab it from 22 | echo.https://www.sphinx-doc.org/ 23 | exit /b 1 24 | ) 25 | 26 | if "%1" == "" goto help 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | # Defining the exact version will make sure things don't break 2 | # Sphinx==6.2.1 3 | sphinx-book-theme==1.0.1 4 | # sphinx-pdj-theme==0.4.0 5 | myst-parser==2.0.0 6 | markdown-it-py==3.0.0 7 | sphinx-copybutton==0.5.2 -------------------------------------------------------------------------------- /docs/source/code.md: -------------------------------------------------------------------------------- 1 | # IP2Location Python API 2 | 3 | ## IP2Location Class 4 | 5 | ```{py:class} IP2Location(database_file_path, file_mode) 6 | Initiate the IP2Location class and load the IP2Location BIN database. 7 | 8 | :param str database_file_path: (Required) The file path links to IP2Location BIN databases. 9 | :param str file_mode: (Optional) The file mode used to open the IP2Location BIN database. Available values are FILE_IO and SHARED_MEMORY. Default is File I/O. 10 | ``` 11 | 12 | ```{py:function} get_all(ip_address) 13 | Retrieve geolocation information for an IP address. 14 | 15 | :param str ip_address: (Required) The IP address (IPv4 or IPv6). 16 | :return: Returns the geolocation information in dict. Refer below table for the fields avaliable in the dict 17 | :rtype: dict 18 | 19 | **RETURN FIELDS** 20 | 21 | | Field Name | Description | 22 | | ---------------- | ------------------------------------------------------------ | 23 | | country_short | Two-character country code based on ISO 3166. | 24 | | country_long | Country name based on ISO 3166. | 25 | | region | Region or state name. | 26 | | city | City name. | 27 | | isp | Internet Service Provider or company\'s name. | 28 | | latitude | City latitude. Defaults to capital city latitude if city is unknown. | 29 | | longitude | City longitude. Defaults to capital city longitude if city is unknown. | 30 | | domain | Internet domain name associated with IP address range. | 31 | | zipcode | ZIP code or Postal code. [172 countries supported](https://www.ip2location.com/zip-code-coverage). | 32 | | timezone | UTC time zone (with DST supported). | 33 | | netspeed | Internet connection type. | 34 | | idd_code | The IDD prefix to call the city from another country. | 35 | | area_code | A varying length number assigned to geographic areas for calls between cities. [223 countries supported](https://www.ip2location.com/area-code-coverage). | 36 | | weather_code | The special code to identify the nearest weather observation station. | 37 | | weather_name | The name of the nearest weather observation station. | 38 | | mcc | Mobile Country Codes (MCC) as defined in ITU E.212 for use in identifying mobile stations in wireless telephone networks, particularly GSM and UMTS networks. | 39 | | mnc | Mobile Network Code (MNC) is used in combination with a Mobile Country Code(MCC) to uniquely identify a mobile phone operator or carrier. | 40 | | mobile_brand | Commercial brand associated with the mobile carrier. You may click [mobile carrier coverage](https://www.ip2location.com/mobile-carrier-coverage) to view the coverage report. | 41 | | elevation | Average height of city above sea level in meters (m). | 42 | | usage_type | Usage type classification of ISP or company. | 43 | | address_type | IP address types as defined in Internet Protocol version 4 (IPv4) and Internet Protocol version 6 (IPv6). | 44 | | category | The domain category based on [IAB Tech Lab Content Taxonomy](https://www.ip2location.com/free/iab-categories). | 45 | | district | District or county name. | 46 | | asn | Autonomous system number (ASN). BIN databases. | 47 | | as_name | Autonomous system (AS) name. | 48 | ``` 49 | 50 | ## IP2LocationIPTools Class 51 | 52 | ```{py:class} IP2LocationIPTools() 53 | Initiate IP2LocationIPTools class. 54 | ``` 55 | 56 | ```{py:function} is_ipv4(ip_address) 57 | Verify if a string is a valid IPv4 address. 58 | 59 | :param str ip_address: (Required) IP address. 60 | :return: Return True if the IP address is a valid IPv4 address or False if it isn't a valid IPv4 address. 61 | :rtype: boolean 62 | ``` 63 | 64 | ```{py:function} is_ipv6(ip_address) 65 | Verify if a string is a valid IPv6 address 66 | 67 | :param str ip_address: (Required) IP address. 68 | :return: Return True if the IP address is a valid IPv6 address or False if it isn't a valid IPv6 address. 69 | :rtype: boolean 70 | ``` 71 | 72 | ```{py:function} ipv4_to_decimal(ip_address) 73 | Translate IPv4 address from dotted-decimal address to decimal format. 74 | 75 | :param str ip_address: (Required) IPv4 address. 76 | :return: Return the decimal format of the IPv4 address. 77 | :rtype: int 78 | ``` 79 | 80 | ```{py:function} decimal_to_ipv4(ip_number) 81 | Translate IPv4 address from decimal number to dotted-decimal address. 82 | 83 | :param str ip_number: (Required) Decimal format of the IPv4 address. 84 | :return: Returns the dotted-decimal format of the IPv4 address. 85 | :rtype: string 86 | ``` 87 | 88 | ```{py:function} ipv6_to_decimal(ip_address) 89 | Translate IPv6 address from hexadecimal address to decimal format. 90 | 91 | :param str ip_address: (Required) IPv6 address. 92 | :return: Return the decimal format of the IPv6 address. 93 | :rtype: int 94 | ``` 95 | 96 | ```{py:function} decimal_to_ipv6(ip_number) 97 | Translate IPv6 address from decimal number into hexadecimal address. 98 | 99 | :param str ip_number: (Required) Decimal format of the IPv6 address. 100 | :return: Returns the hexadecimal format of the IPv6 address. 101 | :rtype: string 102 | ``` 103 | 104 | ```{py:function} ipv4_to_cidr(ip_from, ip_to) 105 | Convert IPv4 range into a list of IPv4 CIDR notation. 106 | 107 | :param str ip_from: (Required) The starting IPv4 address in the range. 108 | :param str ip_to: (Required) The ending IPv4 address in the range. 109 | :return: Returns the list of IPv4 CIDR notation. 110 | :rtype: list 111 | ``` 112 | 113 | ```{py:function} cidr_to_ipv4(cidr) 114 | Convert IPv4 CIDR notation into a list of IPv4 addresses. 115 | 116 | :param str cidr: (Required) IPv4 CIDR notation. 117 | :return: Returns an array of IPv4 addresses. 118 | :rtype: dict 119 | ``` 120 | 121 | ```{py:function} ipv6_to_cidr(ip_from, ip_to) 122 | Convert IPv6 range into a list of IPv6 CIDR notation. 123 | 124 | :param str ip_from: (Required) The starting IPv6 address in the range. 125 | :param str ip_to: (Required) The ending IPv6 address in the range. 126 | :return: Returns the list of IPv6 CIDR notation. 127 | :rtype: list 128 | ``` 129 | 130 | ```{py:function} cidr_to_ipv6(cidr) 131 | Convert IPv6 CIDR notation into a list of IPv6 addresses. 132 | 133 | :param str cidr: (Required) IPv6 CIDR notation. 134 | :return: Returns an array of IPv6 addresses. 135 | :rtype: dict 136 | ``` 137 | 138 | 139 | ```{py:function} compressed_ipv6(ip_address) 140 | Compress a IPv6 to shorten the length. 141 | 142 | :param str ip_address: (Required) IPv6 address. 143 | :return: Returns the compressed version of IPv6 address. 144 | :rtype: str 145 | ``` 146 | 147 | ```{py:function} expand_ipv6(ip_address) 148 | Expand a shorten IPv6 to full length. 149 | 150 | :param str ip_address: (Required) IPv6 address. 151 | :return: Returns the extended version of IPv6 address. 152 | :rtype: str 153 | ``` 154 | 155 | ## Country Class 156 | 157 | ```{py:class} Country(csv_file_path) 158 | Initiate Country class and load the IP2Location Country Information CSV file. This database is free for download at . 159 | 160 | :param str csv_file_path: (Required) The file path links to IP2Location Country Information CSV file. 161 | ``` 162 | 163 | ```{py:function} get_country_info(country_code) 164 | Provide a ISO 3166 country code to get the country information in array. Will return a full list of countries information if country code not provided. 165 | 166 | :param str country_code: (Required) The ISO 3166 country code of a country. 167 | :return: Returns the country information in dict. Refer below table for the fields avaliable in the dict. 168 | :rtype: dict 169 | 170 | **RETURN FIELDS** 171 | 172 | | Field Name | Description | 173 | | ---------------- | ------------------------------------------------------------ | 174 | | country_code | Two-character country code based on ISO 3166. | 175 | | country_alpha3_code | Three-character country code based on ISO 3166. | 176 | | country_numeric_code | Three-character country code based on ISO 3166. | 177 | | capital | Capital of the country. | 178 | | country_demonym | Demonym of the country. | 179 | | total_area | Total area in km{sup}`2`. | 180 | | population | Population of year 2014. | 181 | | idd_code | The IDD prefix to call the city from another country. | 182 | | currency_code | Currency code based on ISO 4217. | 183 | | currency_name | Currency name. | 184 | | currency_symbol | Currency symbol. | 185 | | lang_code | Language code based on ISO 639. | 186 | | lang_name | Language name. | 187 | | cctld | Country-Code Top-Level Domain. | 188 | ``` 189 | 190 | ## Region Class 191 | 192 | ```{py:class} Region(csv_file_path) 193 | Initiate Region class and load the IP2Location ISO 3166-2 Subdivision Code CSV file. This database is free for download at 194 | 195 | :param str csv_file_path: (Required) The file path links to IP2Location ISO 3166-2 Subdivision Code CSV file. 196 | ``` 197 | 198 | ```{py:function} get_region_code(country_code, region_name) 199 | Provide a ISO 3166 country code and the region name to get ISO 3166-2 subdivision code for the region. 200 | 201 | :param str country_code: (Required) Two-character country code based on ISO 3166. 202 | :param str region_name: (Required) Region or state name. 203 | :return: Returns the ISO 3166-2 subdivision code of the region. 204 | :rtype: str 205 | ``` 206 | -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # Read https://www.sphinx-doc.org/en/master/usage/configuration.html for more options available 3 | 4 | # import sphinx_pdj_theme 5 | 6 | # -- Project information 7 | 8 | project = 'IP2Location' 9 | copyright = '2023, IP2Location' 10 | author = 'IP2Location' 11 | 12 | release = '8.10.0' 13 | version = '8.10.0' 14 | 15 | # -- General configuration 16 | 17 | extensions = [ 18 | 'sphinx.ext.duration', 19 | 'sphinx.ext.doctest', 20 | # 'sphinx.ext.autodoc', 21 | # 'sphinx.ext.autosummary', 22 | # 'sphinx.ext.intersphinx', 23 | 'myst_parser', 24 | 'sphinx_copybutton', 25 | # "sphinxext.opengraph", 26 | ] 27 | 28 | # https://myst-parser.readthedocs.io/en/latest/syntax/optional.html 29 | 30 | myst_enable_extensions = [ 31 | # "amsmath", 32 | # "attrs_inline", 33 | "colon_fence", 34 | "deflist", 35 | # "dollarmath", 36 | "fieldlist", 37 | # "html_admonition", 38 | # "html_image", 39 | # "linkify", 40 | # "replacements", 41 | # "smartquotes", 42 | # "strikethrough", 43 | # "substitution", 44 | # "tasklist", 45 | ] 46 | 47 | # https://myst-parser.readthedocs.io/en/latest/configuration.html#setting-html-metadata 48 | # language = "en" 49 | myst_html_meta = { 50 | # "description lang=en": "metadata description", 51 | # "description lang=fr": "description des métadonnées", 52 | "description": "IP2Location Python library enables user to query the geolocation information for an IP address.", 53 | "keywords": "IP2Location, Geolocation, IP location", 54 | "google-site-verification": "DeW6mXDyMnMt4i61ZJBNuoADPimo5266DKob7Z7d6i4", 55 | # "property=og:locale": "en_US" 56 | } 57 | 58 | # OpenGraph metadata 59 | ogp_site_url = "https://ip2location-python.readthedocs.io/en/latest" 60 | 61 | # ogp_custom_meta_tags = [ 62 | # '', 63 | # ] 64 | 65 | # intersphinx_mapping = { 66 | # 'python': ('https://docs.python.org/3/', None), 67 | # 'sphinx': ('https://www.sphinx-doc.org/en/master/', None), 68 | # } 69 | # intersphinx_disabled_domains = ['std'] 70 | 71 | # templates_path = ['_templates'] 72 | 73 | # -- Options for HTML output 74 | 75 | html_theme = 'sphinx_book_theme' 76 | 77 | # PDJ theme options, see the list of available options here: https://github.com/jucacrispim/sphinx_pdj_theme/blob/master/sphinx_pdj_theme/theme.conf 78 | html_theme_options = { 79 | "use_edit_page_button": False, 80 | "use_source_button": False, 81 | "use_issues_button": False, 82 | "use_download_button": False, 83 | "use_sidenotes": False, 84 | } 85 | 86 | # The name of an image file (relative to this directory) to place at the top 87 | # of the sidebar. 88 | html_logo = 'images/ipl-logo-square-1200.png' 89 | 90 | # Favicon 91 | html_favicon = 'images/favicon.ico' 92 | 93 | html_title = "IP2Location Python" 94 | 95 | # html_extra_path = ["googlead5f0f82eb100b8b.html"] 96 | 97 | html_baseurl = "https://ip2location-python.readthedocs.io/en/latest/" -------------------------------------------------------------------------------- /docs/source/googlead5f0f82eb100b8b.html: -------------------------------------------------------------------------------- 1 | google-site-verification: googlead5f0f82eb100b8b.html -------------------------------------------------------------------------------- /docs/source/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrislim2888/IP2Location-Python/fcc8811a9393275c4e1aea01841f5d6c6e25e669/docs/source/images/favicon.ico -------------------------------------------------------------------------------- /docs/source/images/ipl-logo-square-1200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrislim2888/IP2Location-Python/fcc8811a9393275c4e1aea01841f5d6c6e25e669/docs/source/images/ipl-logo-square-1200.png -------------------------------------------------------------------------------- /docs/source/index.md: -------------------------------------------------------------------------------- 1 | # IP2Location Python Library 2 | 3 | ![PyPI](https://img.shields.io/pypi/v/IP2Location) 4 | ![PyPI - Downloads](https://img.shields.io/pypi/dm/IP2Location) 5 | ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/ip2location) 6 | 7 | 8 | This is a [IP2Location](https://www.ip2location.com/) Python library that enables the user to find the country, region or state, district, city, latitude, longitude, ZIP code, time zone, ISP, domain name, connection speed, IDD code, area code, weather station code, weather station name, MNC, MCC, mobile brand, elevation, usage type, address type, IAB category and ASN by IP address or hostname originates from. The library reads the geo location information from **IP2Location BIN database**. 9 | 10 | Supported IPv4 and IPv6 address. 11 | 12 | ## Table of contents 13 | ```{eval-rst} 14 | .. toctree:: 15 | 16 | self 17 | quickstart 18 | code 19 | ``` -------------------------------------------------------------------------------- /docs/source/quickstart.md: -------------------------------------------------------------------------------- 1 | # Quickstart 2 | 3 | ## Dependencies 4 | 5 | This library requires IP2Location BIN database to function. You may 6 | download the BIN database at 7 | 8 | - IP2Location LITE BIN Data (Free): 9 | - IP2Location Commercial BIN Data (Comprehensive): 10 | 11 | 12 | :::{note} 13 | An outdated BIN database was provided in the databases folder for your testing. You are recommended to visit the above links to download the latest BIN database. 14 | ::: 15 | 16 | ## Requirements 17 | 18 | 1. Python 3.5 and above. 19 | 20 | ## Installation 21 | 22 | ### Manual Installation 23 | 24 | 1. Unzip the package. 25 | 2. Execute python setup.py build 26 | 3. Execute python setup.py install 27 | 28 | ### Installation using PyPI. 29 | 30 | ``` bash 31 | pip install IP2Location 32 | ``` 33 | 34 | ### Installation in Arch Linux 35 | 36 | For Arch Linux user, you can install the module using the following command: 37 | ```Bash 38 | git clone https://aur.archlinux.org/ip2location-python.git && cd ip2location-io-python 39 | makepkg -si 40 | ``` 41 | 42 | ## Sample Codes 43 | 44 | ### Query geolocation information from BIN database 45 | 46 | You can query the geolocation information from the IP2Location BIN 47 | database as below: 48 | 49 | ``` python 50 | import os 51 | import IP2Location 52 | 53 | """ 54 | Cache the database into memory to accelerate lookup speed. 55 | WARNING: Please make sure your system have sufficient RAM to use this feature. 56 | """ 57 | # database = IP2Location.IP2Location(os.path.join("data", "IPV6-COUNTRY.BIN"), "SHARED_MEMORY") 58 | 59 | # Default file I/O lookup 60 | database = IP2Location.IP2Location(os.path.join("data", "IPV6-COUNTRY.BIN")) 61 | 62 | rec = database.get_all("19.5.10.1") 63 | 64 | print("Country Code : " + rec.country_short) 65 | print("Country Name : " + rec.country_long) 66 | print("Region Name : " + rec.region) 67 | print("City Name : " + rec.city) 68 | print("ISP Name : " + rec.isp) 69 | print("Latitude : " + rec.latitude) 70 | print("Longitude : " + rec.longitude) 71 | print("Domain Name : " + rec.domain) 72 | print("ZIP Code : " + rec.zipcode) 73 | print("Time Zone : " + rec.timezone) 74 | print("Net Speed : " + rec.netspeed) 75 | print("Area Code : " + rec.idd_code) 76 | print("IDD Code : " + rec.area_code) 77 | print("Weather Station Code : " + rec.weather_code) 78 | print("Weather Station Name : " + rec.weather_name) 79 | print("MCC : " + rec.mcc) 80 | print("MNC : " + rec.mnc) 81 | print("Mobile Carrier : " + rec.mobile_brand) 82 | print("Elevation : " + rec.elevation) 83 | print("Usage Type : " + rec.usage_type) 84 | print("Address Type : " + rec.address_type) 85 | print("Category : " + rec.category) 86 | print("District : " + rec.district) 87 | print("ASN : " + rec.asn) 88 | print("AS : " + rec.as_name) 89 | print("\nYou may download the DB26 sample BIN at http://www.ip2location.com/downloads/sample6.bin.db26.zip for full data display.") 90 | ``` 91 | 92 | ### Processing IP address using IP Tools class 93 | 94 | You can manupulate IP address, IP number and CIDR as below: 95 | 96 | ``` python 97 | import IP2Location 98 | ipTools = IP2Location.IP2LocationIPTools() 99 | print(str(ipTools.is_ipv4("8.8.8.8"))) 100 | print(str(ipTools.is_ipv6("2001:4860:4860::8888"))) 101 | print(ipTools.ipv4_to_decimal("8.8.8.8")) 102 | print(ipTools.decimal_to_ipv4(134744072)) 103 | print(ipTools.ipv6_to_decimal("2001:4860:4860::8888")) 104 | print(ipTools.decimal_to_ipv6(42541956123769884636017138956568135816)) 105 | print(ipTools.ipv4_to_cidr("8.0.0.0", "8.255.255.255")) 106 | print(ipTools.cidr_to_ipv4("8.0.0.0/8")) 107 | print(ipTools.ipv6_to_cidr("2002:0000:0000:1234:abcd:ffff:c0a8:0000", "2002:0000:0000:1234:ffff:ffff:ffff:ffff")) 108 | print(ipTools.cidr_to_ipv6("2002::1234:abcd:ffff:c0a8:101/64")) 109 | print(ipTools.compressed_ipv6("2002:0000:0000:1234:FFFF:FFFF:FFFF:FFFF")) 110 | print(ipTools.expand_ipv6("2002::1234:FFFF:FFFF:FFFF:FFFF")) 111 | ``` 112 | 113 | ### List down country information 114 | 115 | You can query country information for a country from IP2Location Country 116 | Information CSV file as below: 117 | 118 | ``` python 119 | import os 120 | import IP2Location 121 | 122 | # List country information 123 | country = IP2Location.Country(os.path.join("data", "IP2LOCATION-COUNTRY-INFORMATION-BASIC.CSV")) 124 | print(country.get_country_info("US")) 125 | ``` 126 | 127 | ### List down region information 128 | 129 | You can get the region code by country code and region name from 130 | IP2Location ISO 3166-2 Subdivision Code CSV file as below: 131 | 132 | ``` python 133 | import os 134 | import IP2Location 135 | 136 | # Get region code by country code and region 137 | region = IP2Location.Region(os.path.join("data", "IP2LOCATION-ISO3166-2.CSV") 138 | print(region.get_region_code("US", "California")) 139 | ``` 140 | -------------------------------------------------------------------------------- /lookup.py: -------------------------------------------------------------------------------- 1 | import os, IP2Location, sys, ipaddress 2 | 3 | # database = IP2Location.IP2Location(os.path.join("data", "IPV6-COUNTRY.BIN"), "SHARED_MEMORY") 4 | database = IP2Location.IP2Location(os.path.join("data", "IPV6-COUNTRY.BIN")) 5 | 6 | try: 7 | ip = sys.argv[1] 8 | 9 | if ip == '' : 10 | print ('You cannot enter an empty IP address.') 11 | sys.exit(1) 12 | else: 13 | try: 14 | ipaddress.ip_address(ip) 15 | except ValueError: 16 | print ('Invalid IP address') 17 | sys.exit(1) 18 | 19 | rec = database.get_all(ip) 20 | print (rec) 21 | 22 | except IndexError: 23 | print ("Please enter an IP address to continue.") 24 | 25 | database.close() -------------------------------------------------------------------------------- /sample.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2005-2024 IP2Location.com 2 | # All Rights Reserved 3 | # 4 | # This library is free software: you can redistribute it and/or 5 | # modify it under the terms of the MIT license 6 | 7 | import os 8 | import IP2Location 9 | 10 | """ 11 | Cache the database into memory to accelerate lookup speed. 12 | WARNING: Please make sure your system have sufficient RAM to use this feature. 13 | """ 14 | # database = IP2Location.IP2Location(os.path.join("data", "IPV6-COUNTRY.BIN"), "SHARED_MEMORY") 15 | 16 | # Default file I/O lookup 17 | database = IP2Location.IP2Location(os.path.join("data", "IPV6-COUNTRY.BIN")) 18 | 19 | rec = database.get_all("19.5.10.1") 20 | 21 | print("Country Code : " + rec.country_short) 22 | print("Country Name : " + rec.country_long) 23 | print("Region Name : " + rec.region) 24 | print("City Name : " + rec.city) 25 | print("ISP Name : " + rec.isp) 26 | print("Latitude : " + rec.latitude) 27 | print("Longitude : " + rec.longitude) 28 | print("Domain Name : " + rec.domain) 29 | print("ZIP Code : " + rec.zipcode) 30 | print("Time Zone : " + rec.timezone) 31 | print("Net Speed : " + rec.netspeed) 32 | print("Area Code : " + rec.idd_code) 33 | print("IDD Code : " + rec.area_code) 34 | print("Weather Station Code : " + rec.weather_code) 35 | print("Weather Station Name : " + rec.weather_name) 36 | print("MCC : " + rec.mcc) 37 | print("MNC : " + rec.mnc) 38 | print("Mobile Carrier : " + rec.mobile_brand) 39 | print("Elevation : " + rec.elevation) 40 | print("Usage Type : " + rec.usage_type) 41 | print("Address Type : " + rec.address_type) 42 | print("Category : " + rec.category) 43 | print("District : " + rec.district) 44 | print("ASN : " + rec.asn) 45 | print("AS : " + rec.as_name) 46 | print("\nYou may download the DB26 sample BIN at http://www.ip2location.com/downloads/sample6.bin.db26.zip for full data display.") 47 | 48 | # Web Service 49 | ws = IP2Location.IP2LocationWebService("demo","WS25",True) 50 | rec = ws.lookup("8.8.8.8", ["continent", "country", "region", "city", "geotargeting", "country_groupings", "time_zone_info"], "en") 51 | print (rec) 52 | print ("\n") 53 | print ("Credit Remaining: {}\n".format(ws.getcredit())) 54 | 55 | # IP Tools 56 | ipTools = IP2Location.IP2LocationIPTools() 57 | print(str(ipTools.is_ipv4("8.8.8.8"))) 58 | print(str(ipTools.is_ipv6("2001:4860:4860::8888"))) 59 | print(ipTools.ipv4_to_decimal("8.8.8.8")) 60 | print(ipTools.decimal_to_ipv4(134744072)) 61 | print(ipTools.ipv6_to_decimal("2001:4860:4860::8888")) 62 | print(ipTools.decimal_to_ipv6(42541956123769884636017138956568135816)) 63 | print(ipTools.ipv4_to_cidr("8.0.0.0", "8.255.255.255")) 64 | print(ipTools.cidr_to_ipv4("8.0.0.0/8")) 65 | print(ipTools.ipv6_to_cidr("2002:0000:0000:1234:abcd:ffff:c0a8:0000", "2002:0000:0000:1234:ffff:ffff:ffff:ffff")) 66 | print(ipTools.cidr_to_ipv6("2002::1234:abcd:ffff:c0a8:101/64")) 67 | print(ipTools.compressed_ipv6("2002:0000:0000:1234:FFFF:FFFF:FFFF:FFFF")) 68 | print(ipTools.expand_ipv6("2002::1234:FFFF:FFFF:FFFF:FFFF")) 69 | 70 | # List country information 71 | country = IP2Location.Country(os.path.join("data", "IP2LOCATION-COUNTRY-INFORMATION-BASIC.CSV")) 72 | print(country.get_country_info("US")) 73 | 74 | # Get region code by country code and region 75 | region = IP2Location.Region(os.path.join("data", "IP2LOCATION-ISO3166-2.CSV")) 76 | print(region.get_region_code("US", "California")) -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import setuptools 2 | 3 | with open("README.md", "r") as fh: 4 | long_description = fh.read() 5 | 6 | setuptools.setup( 7 | name="IP2Location", 8 | version="8.10.5", 9 | author="IP2Location", 10 | author_email="support@ip2location.com", 11 | description="This is an IP geolocation library that enables the user to find the country, region, city, latitude and longitude, ZIP code, time zone, ISP, domain name, area code, weather info, mobile info, elevation, usage type, address type and IAB category from an IP address. It supports both IPv4 and IPv6 lookup.", 12 | long_description=long_description, 13 | long_description_content_type="text/markdown", 14 | url="https://github.com/chrislim2888/ip2location-python", 15 | packages=setuptools.find_packages(), 16 | tests_require=['pytest>=3.0.6'], 17 | classifiers=[ 18 | "Development Status :: 5 - Production/Stable", 19 | "Intended Audience :: Developers", 20 | "Topic :: Software Development :: Libraries :: Python Modules", 21 | "Programming Language :: Python :: 3.5", 22 | "Programming Language :: Python :: 3.6", 23 | "Programming Language :: Python :: 3.7", 24 | "Programming Language :: Python :: 3.8", 25 | "Programming Language :: Python :: 3.9", 26 | "Programming Language :: Python :: 3.10", 27 | "Programming Language :: Python :: 3.11", 28 | "Programming Language :: Python :: 3.12", 29 | "Programming Language :: Python :: 3.13", 30 | "Programming Language :: Python :: Implementation :: CPython", 31 | "Programming Language :: Python :: Implementation :: PyPy", 32 | "License :: OSI Approved :: MIT License", 33 | "Operating System :: OS Independent", 34 | ], 35 | ) 36 | -------------------------------------------------------------------------------- /test.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2005-2024 IP2Location.com 2 | # All Rights Reserved 3 | # 4 | # This library is free software: you can redistribute it and/or 5 | # modify it under the terms of the MIT license 6 | 7 | 8 | import os 9 | import sys 10 | import IP2Location 11 | 12 | database = IP2Location.IP2Location() 13 | 14 | passed = 0 15 | failed = 0 16 | test_num = 0 17 | 18 | database.open(os.path.join("data", "IP-COUNTRY.BIN")) 19 | for line in open(os.path.join("data", "country_test_ipv4_data.txt")): 20 | addr, country_short = line.strip().split() 21 | rec = database.get_all(addr) 22 | 23 | test_num += 1 24 | if rec is not None: 25 | if rec.country_short != country_short: 26 | failed += 1 27 | print("Test IP Address %s (Test %d) failed. We got %s but expected %s" \ 28 | % (addr, test_num, rec and rec.country_short or 'None', country_short)) 29 | else: 30 | passed += 1 31 | 32 | database.open(os.path.join("data", "IPV6-COUNTRY.BIN")) 33 | for line in open(os.path.join("data", "country_test_ipv6_data.txt")): 34 | addr, country_short = line.strip().split() 35 | rec = database.get_all(addr) 36 | 37 | test_num += 1 38 | if rec is not None: 39 | if rec.country_short != country_short: 40 | failed += 1 41 | print("Test IP Address %s (Test %d) failed. We got %s but expected %s" \ 42 | % (addr, test_num, rec and rec.country_short or 'None', country_short)) 43 | else: 44 | passed += 1 45 | 46 | print('PASS: %d' % (passed)) 47 | print('FAIL: %d' % (failed)) 48 | -------------------------------------------------------------------------------- /tests/test_country.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import pytest 4 | 5 | import os, IP2Location 6 | 7 | country = IP2Location.Country(os.path.join("data", "IP2LOCATION-COUNTRY-INFORMATION-BASIC.CSV")) 8 | 9 | def test_country_code_field(): 10 | country_information = country.get_country_info("US") 11 | assert "country_code" in country_information 12 | 13 | def test_country_code_value(): 14 | country_information = country.get_country_info("US") 15 | assert country_information["country_code"] == "US" 16 | 17 | def test_capital(): 18 | country_information = country.get_country_info("MY") 19 | assert country_information["capital"] == "Kuala Lumpur" -------------------------------------------------------------------------------- /tests/test_database.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import pytest 4 | 5 | import os, IP2Location 6 | 7 | ipv4database = os.path.join("data", "IP2LOCATION-LITE-DB1.BIN") 8 | 9 | ipv6database = os.path.join("data", "IP2LOCATION-LITE-DB1.IPV6.BIN") 10 | 11 | def testinvaliddatabase(): 12 | try: 13 | database = IP2Location.IP2Location(os.path.join("data", "NULL.BIN")) 14 | except ValueError as e: 15 | assert "The database file does not seem to exist." == str(e) 16 | 17 | def testfunctionexist(): 18 | database = IP2Location.IP2Location(ipv4database) 19 | functions_list = ['open', 'close', 'get_all', 'get_country_short', 'get_country_long', 'get_region', 'get_city', 'get_latitude', 'get_longitude', 'get_isp', 'get_domain', 'get_zipcode', 'get_timezone', 'get_netspeed', 'get_idd_code', 'get_area_code', 'get_weather_code', 'get_weather_name', 'get_mcc', 'get_mnc', 'get_mobile_brand', 'get_elevation', 'get_usage_type', 'get_district', 'get_asn', 'get_as'] 20 | for x in range(len(functions_list)): 21 | assert hasattr(database, functions_list[x]) == True, "Function did not exist." 22 | 23 | def testipv4countrycode(): 24 | database = IP2Location.IP2Location(ipv4database) 25 | rec = database.get_all("8.8.8.8") 26 | assert rec.country_short == "US", "Test failed because country code not same." 27 | 28 | def testipv4countryname(): 29 | database = IP2Location.IP2Location(ipv4database) 30 | rec = database.get_all("8.8.8.8") 31 | assert rec.country_long == "United States of America", "Test failed because country name not same." 32 | 33 | def testgetcountryshort(): 34 | database = IP2Location.IP2Location(ipv4database) 35 | rec = database.get_country_short("8.8.8.8") 36 | assert rec == "US", "Test failed because country code not same." 37 | 38 | def testgetcountrylong(): 39 | database = IP2Location.IP2Location(ipv4database) 40 | rec = database.get_country_long("8.8.8.8") 41 | assert rec == "United States of America", "Test failed because country name not same." 42 | 43 | def testgetregion(): 44 | database = IP2Location.IP2Location(ipv4database) 45 | rec = database.get_region("8.8.8.8") 46 | assert rec == None 47 | 48 | def testgetcity(): 49 | database = IP2Location.IP2Location(ipv4database) 50 | rec = database.get_city("8.8.8.8") 51 | assert rec == None 52 | 53 | def testgetlatitude(): 54 | database = IP2Location.IP2Location(ipv4database) 55 | rec = database.get_latitude("8.8.8.8") 56 | assert rec == None 57 | 58 | def testgetlongitude(): 59 | database = IP2Location.IP2Location(ipv4database) 60 | rec = database.get_longitude("8.8.8.8") 61 | assert rec == None 62 | 63 | def testgetisp(): 64 | database = IP2Location.IP2Location(ipv4database) 65 | rec = database.get_isp("8.8.8.8") 66 | assert rec == None 67 | 68 | def testgetdomain(): 69 | database = IP2Location.IP2Location(ipv4database) 70 | rec = database.get_domain("8.8.8.8") 71 | assert rec == None 72 | 73 | def testgetzipcode(): 74 | database = IP2Location.IP2Location(ipv4database) 75 | rec = database.get_zipcode("8.8.8.8") 76 | assert rec == None 77 | 78 | def testgettimezone(): 79 | database = IP2Location.IP2Location(ipv4database) 80 | rec = database.get_timezone("8.8.8.8") 81 | assert rec == None 82 | 83 | def testgetnetspeed(): 84 | database = IP2Location.IP2Location(ipv4database) 85 | rec = database.get_netspeed("8.8.8.8") 86 | assert rec == None 87 | 88 | def testgetiddcode(): 89 | database = IP2Location.IP2Location(ipv4database) 90 | rec = database.get_idd_code("8.8.8.8") 91 | assert rec == None 92 | 93 | def testgetareacode(): 94 | database = IP2Location.IP2Location(ipv4database) 95 | rec = database.get_area_code("8.8.8.8") 96 | assert rec == None 97 | 98 | def testgetweathercode(): 99 | database = IP2Location.IP2Location(ipv4database) 100 | rec = database.get_weather_code("8.8.8.8") 101 | assert rec == None 102 | 103 | def testgetweathername(): 104 | database = IP2Location.IP2Location(ipv4database) 105 | rec = database.get_weather_name("8.8.8.8") 106 | assert rec == None 107 | 108 | def testgetmcc(): 109 | database = IP2Location.IP2Location(ipv4database) 110 | rec = database.get_mcc("8.8.8.8") 111 | assert rec == None 112 | 113 | def testgetmnc(): 114 | database = IP2Location.IP2Location(ipv4database) 115 | rec = database.get_mnc("8.8.8.8") 116 | assert rec == None 117 | 118 | def testgetmobilebrand(): 119 | database = IP2Location.IP2Location(ipv4database) 120 | rec = database.get_mobile_brand("8.8.8.8") 121 | assert rec == None 122 | 123 | def testgetelevation(): 124 | database = IP2Location.IP2Location(ipv4database) 125 | rec = database.get_elevation("8.8.8.8") 126 | assert rec == None 127 | 128 | def testgetusagetype(): 129 | database = IP2Location.IP2Location(ipv4database) 130 | rec = database.get_usage_type("8.8.8.8") 131 | assert rec == None 132 | 133 | def testgetdistrict(): 134 | database = IP2Location.IP2Location(ipv4database) 135 | rec = database.get_district("8.8.8.8") 136 | assert rec == None 137 | 138 | def testgetasn(): 139 | database = IP2Location.IP2Location(ipv4database) 140 | rec = database.get_asn("8.8.8.8") 141 | assert rec == None 142 | 143 | def testgetas(): 144 | database = IP2Location.IP2Location(ipv4database) 145 | rec = database.get_as("8.8.8.8") 146 | assert rec == None 147 | 148 | def testipv6countrycode(): 149 | database = IP2Location.IP2Location(ipv6database) 150 | rec = database.get_all("2001:4860:4860::8888") 151 | assert rec.country_short == "US", "Test failed because country code not same." 152 | 153 | def testipv6countryname(): 154 | database = IP2Location.IP2Location(ipv6database) 155 | rec = database.get_all("2001:4860:4860::8888") 156 | assert rec.country_long == "United States of America", "Test failed because country name not same." 157 | 158 | def testipv6unsupportedfield(): 159 | database = IP2Location.IP2Location(ipv6database) 160 | rec = database.get_all("2001:4860:4860::8888") 161 | assert rec.city == None, "Test failed because city name not same." -------------------------------------------------------------------------------- /tests/test_iptools.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import pytest 4 | 5 | import IP2Location 6 | 7 | ipTools = IP2Location.IP2LocationIPTools() 8 | 9 | def testipv4(): 10 | assert ipTools.is_ipv4('8.8.8.8') == True 11 | 12 | def testinvalidipv4(): 13 | assert ipTools.is_ipv4('8.8.8.555') == False 14 | 15 | def testipv6(): 16 | assert ipTools.is_ipv6('2001:4860:4860::8888') == True 17 | 18 | def testinvalidipv6(): 19 | assert ipTools.is_ipv6('2001:4860:4860::ZZZZ') == False 20 | 21 | def testipv4decimal(): 22 | assert ipTools.ipv4_to_decimal('8.8.8.8') == 134744072 23 | 24 | def testdecimalipv4(): 25 | assert ipTools.decimal_to_ipv4(134744072) == '8.8.8.8' 26 | 27 | def testipv6decimal(): 28 | assert ipTools.ipv6_to_decimal('2001:4860:4860::8888') == 42541956123769884636017138956568135816 29 | 30 | def testdecimalipv6(): 31 | assert ipTools.decimal_to_ipv6(42541956123769884636017138956568135816) == '2001:4860:4860::8888' 32 | 33 | def testipv4tocidr(): 34 | assert ipTools.ipv4_to_cidr('8.0.0.0', '8.255.255.255') == ['8.0.0.0/8'] 35 | 36 | def testcidrtoipv4(): 37 | assert ipTools.cidr_to_ipv4('8.0.0.0/8') == {'ip_start': '8.0.0.0', 'ip_end': '8.255.255.255'} 38 | 39 | def testipv6tocidr(): 40 | assert ipTools.ipv6_to_cidr('2002:0000:0000:1234:abcd:ffff:c0a8:0000', '2002:0000:0000:1234:ffff:ffff:ffff:ffff') == ['2002::1234:abcd:ffff:c0a8:0/109', '2002::1234:abcd:ffff:c0b0:0/108', '2002::1234:abcd:ffff:c0c0:0/106', '2002::1234:abcd:ffff:c100:0/104', '2002::1234:abcd:ffff:c200:0/103', '2002::1234:abcd:ffff:c400:0/102', '2002::1234:abcd:ffff:c800:0/101', '2002::1234:abcd:ffff:d000:0/100', '2002::1234:abcd:ffff:e000:0/99', '2002:0:0:1234:abce::/79', '2002:0:0:1234:abd0::/76', '2002:0:0:1234:abe0::/75', '2002:0:0:1234:ac00::/70', '2002:0:0:1234:b000::/68', '2002:0:0:1234:c000::/66'] 41 | 42 | def testcidrtoipv6(): 43 | assert ipTools.cidr_to_ipv6('2002::1234:abcd:ffff:c0a8:101/64') == {'ip_start': '2002:0000:0000:1234:abcd:ffff:c0a8:0101', 'ip_end': '2002:0000:0000:1234:ffff:ffff:ffff:ffff'} 44 | 45 | def testcompressipv6(): 46 | assert ipTools.compressed_ipv6('2002:0000:0000:1234:FFFF:FFFF:FFFF:FFFF') == '2002::1234:ffff:ffff:ffff:ffff' 47 | 48 | def testexpandipv6(): 49 | assert ipTools.expand_ipv6('2002::1234:FFFF:FFFF:FFFF:FFFF') == '2002:0000:0000:1234:ffff:ffff:ffff:ffff' 50 | -------------------------------------------------------------------------------- /tests/test_region.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import pytest 4 | 5 | import os, IP2Location 6 | 7 | region = IP2Location1.Region(os.path.join("data", "IP2LOCATION-ISO3166-2.CSV") 8 | 9 | def test_region_code(): 10 | region_code = region.get_region_code("US", "California") 11 | assert "US-CA" == region_code -------------------------------------------------------------------------------- /tests/test_webservice.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import pytest 4 | 5 | import IP2Location 6 | 7 | apikey = "demo" 8 | package = "WS24" 9 | usessl = True 10 | addons = ["continent", "country", "region", "city", "geotargeting", "country_groupings", "time_zone_info"] 11 | language = "en" 12 | 13 | ws = IP2Location.IP2LocationWebService(apikey,package,usessl) 14 | 15 | def testcountrycode(): 16 | # ws = IP2Location.IP2LocationWebService(apikey,package,usessl) 17 | rec = ws.lookup("8.8.8.8", addons, language) 18 | assert rec['country_code'] == "US", "Test failed because country code not same." 19 | 20 | def testgetcredit(): 21 | credit = ws.getcredit() 22 | assert str(credit).isdigit() == True, "Test failed because it is no a digit value." 23 | 24 | def testfunctionexist(): 25 | functions_list = ['lookup', 'getcredit'] 26 | for x in range(len(functions_list)): 27 | assert hasattr(ws, functions_list[x]) == True, "Function did not exist." --------------------------------------------------------------------------------