From 7119b363208d70adbeeb1d19d11b599e215ff750 Mon Sep 17 00:00:00 2001 From: secynic Date: Tue, 14 Jan 2014 18:19:48 -0600 Subject: [PATCH] v0.7.0 --- CHANGES.rst | 6 ++ README.rst | 14 ++- ipwhois/__init__.py | 2 +- ipwhois/ipwhois.py | 182 ++++++++++++++++++---------------- ipwhois/tests/test_ipwhois.py | 29 +++++- ipwhois/tests/test_utils.py | 20 +++- ipwhois/utils.py | 5 +- setup.py | 16 ++- 8 files changed, 176 insertions(+), 98 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 095c313..72077ad 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,6 +1,12 @@ Changelog ========= +0.7.0 (2014-01-14) +------------------ + +- Added Python 2.6+ support. +- The country field in net dicts is now forced uppercase. + 0.6.0 (2014-01-13) ------------------ diff --git a/README.rst b/README.rst index b40ad4c..eb2bda1 100644 --- a/README.rst +++ b/README.rst @@ -9,8 +9,6 @@ The various NICs are pretty inconsistent with formatting Whois results and the information contained within. I am still working through how to parse some of these fields in to standard dictionary keys. -This version requires Python 3.3+ (for the ipaddress library) and dnspython3. - Usage Examples ============== @@ -109,6 +107,18 @@ Countries:: United States +Dependencies +============ + +Python 2.6, 2.7:: + + dnspython + ipaddr + +Python 3.3:: + + dnspython3 + Installing ========== diff --git a/ipwhois/__init__.py b/ipwhois/__init__.py index 3975fbe..730c24a 100644 --- a/ipwhois/__init__.py +++ b/ipwhois/__init__.py @@ -22,7 +22,7 @@ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. -__version__ = '0.6.0' +__version__ = '0.7.0' from .ipwhois import (IPWhois, IPDefinedError, ASNLookupError, WhoisLookupError, HostLookupError) diff --git a/ipwhois/ipwhois.py b/ipwhois/ipwhois.py index 86c9ae2..a5b1007 100644 --- a/ipwhois/ipwhois.py +++ b/ipwhois/ipwhois.py @@ -22,13 +22,34 @@ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. -import ipaddress +try: + from ipaddress import (ip_address, + ip_network, + summarize_address_range, + collapse_addresses) +except ImportError: + from ipaddr import (IPAddress as ip_address, + IPNetwork as ip_network, + summarize_address_range, + collapse_address_list as collapse_addresses) + import socket import dns.resolver import re import json from .utils import ipv4_is_defined, ipv6_is_defined -from urllib import request + +try: + from urllib.request import (OpenerDirector, + ProxyHandler, + build_opener, + Request) +except ImportError: + from urllib2 import (OpenerDirector, + ProxyHandler, + build_opener, + Request) + from time import sleep from datetime import datetime @@ -239,20 +260,20 @@ class IPWhois(): def __init__(self, address, timeout=5, proxy_opener=None): #IPv4Address or IPv6Address, use ipaddress package exception handling. - self.address = ipaddress.ip_address(address) + self.address = ip_address(address) #Default timeout for socket connections. self.timeout = timeout #Proxy opener. - if isinstance(proxy_opener, request.OpenerDirector): + if isinstance(proxy_opener, OpenerDirector): self.opener = proxy_opener else: - handler = request.ProxyHandler() - self.opener = request.build_opener(handler) + handler = ProxyHandler() + self.opener = build_opener(handler) #IP address in string format for use in queries. self.address_str = self.address.__str__() @@ -497,7 +518,7 @@ def get_whois(self, asn_registry='arin', retry_count=3): sleep(1) return self.get_whois(asn_registry, retry_count) - return response + return str(response) except (socket.timeout, socket.error): @@ -537,9 +558,12 @@ def get_rws(self, url=None, retry_count=3): try: #Create the connection for the whois query. - conn = request.Request(url, headers={'Accept': 'application/json'}) + conn = Request(url, headers={'Accept': 'application/json'}) data = self.opener.open(conn, timeout=self.timeout) - d = json.loads(data.readall().decode()) + try: + d = json.loads(data.readall().decode()) + except AttributeError: + d = json.loads(data.read().decode('ascii', 'ignore')) return d @@ -676,7 +700,7 @@ def lookup(self, inc_raw=False, retry_count=3): net = BASE_NET.copy() net['cidr'] = ', '.join( - [ipaddress.ip_network(c.strip()).__str__() + [ip_network(c.strip()).__str__() for c in match.group(1).split(', ')] ) net['start'] = match.start() @@ -711,8 +735,7 @@ def lookup(self, inc_raw=False, retry_count=3): addr = '/'.join(addr_split) - temp.append(ipaddress.ip_network( - addr.strip()).__str__()) + temp.append(ip_network(addr.strip()).__str__()) net = BASE_NET.copy() net['cidr'] = ', '.join(temp) @@ -739,19 +762,17 @@ def lookup(self, inc_raw=False, retry_count=3): if match.group(3) and match.group(4): addrs = [] - addrs.extend(ipaddress.summarize_address_range( - ipaddress.ip_address(match.group(3).strip()), - ipaddress.ip_address(match.group(4).strip()))) + addrs.extend(summarize_address_range( + ip_address(match.group(3).strip()), + ip_address(match.group(4).strip()))) cidr = ', '.join( - [i.__str__() - for i in ipaddress.collapse_addresses(addrs)] + [i.__str__() for i in collapse_addresses(addrs)] ) else: - cidr = ipaddress.ip_network( - match.group(2).strip()).__str__() + cidr = ip_network(match.group(2).strip()).__str__() net = BASE_NET.copy() net['cidr'] = cidr @@ -888,13 +909,12 @@ def _lookup_rws_arin(self, response=None, retry_count=3): try: - addrs.extend(ipaddress.summarize_address_range( - ipaddress.ip_address(n['startAddress']['$'].strip()), - ipaddress.ip_address(n['endAddress']['$'].strip()))) + addrs.extend(summarize_address_range( + ip_address(n['startAddress']['$'].strip()), + ip_address(n['endAddress']['$'].strip()))) net['cidr'] = ', '.join( - [i.__str__() - for i in ipaddress.collapse_addresses(addrs)] + [i.__str__() for i in collapse_addresses(addrs)] ) except (KeyError, ValueError, TypeError): @@ -903,7 +923,7 @@ def _lookup_rws_arin(self, response=None, retry_count=3): try: - net['created'] = n['registrationDate']['$'].strip() + net['created'] = str(n['registrationDate']['$']).strip() except KeyError: @@ -911,7 +931,7 @@ def _lookup_rws_arin(self, response=None, retry_count=3): try: - net['updated'] = n['updateDate']['$'].strip() + net['updated'] = str(n['updateDate']['$']).strip() except KeyError: @@ -919,7 +939,7 @@ def _lookup_rws_arin(self, response=None, retry_count=3): try: - net['name'] = n['name']['$'].strip() + net['name'] = str(n['name']['$']).strip() except KeyError: @@ -938,7 +958,7 @@ def _lookup_rws_arin(self, response=None, retry_count=3): try: - net['description'] = n[ref[0]]['@name'].strip() + net['description'] = str(n[ref[0]]['@name']).strip() except KeyError: @@ -965,7 +985,7 @@ def _lookup_rws_arin(self, response=None, retry_count=3): addr_list = [addr_list] net['address'] = '\n'.join( - [line['$'].strip() for line in addr_list] + [str(line['$']).strip() for line in addr_list] ) except KeyError: @@ -975,7 +995,7 @@ def _lookup_rws_arin(self, response=None, retry_count=3): try: net['postal_code'] = ( - ref_response[ref[1]]['postalCode']['$'] + str(ref_response[ref[1]]['postalCode']['$']) ) except KeyError: @@ -984,7 +1004,7 @@ def _lookup_rws_arin(self, response=None, retry_count=3): try: - net['city'] = ref_response[ref[1]]['city']['$'] + net['city'] = str(ref_response[ref[1]]['city']['$']) except KeyError: @@ -993,8 +1013,8 @@ def _lookup_rws_arin(self, response=None, retry_count=3): try: net['country'] = ( - ref_response[ref[1]]['iso3166-1']['code2']['$'] - ) + str(ref_response[ref[1]]['iso3166-1']['code2']['$']) + ).upper() except KeyError: @@ -1003,7 +1023,7 @@ def _lookup_rws_arin(self, response=None, retry_count=3): try: net['state'] = ( - ref_response[ref[1]]['iso3166-2']['$'] + str(ref_response[ref[1]]['iso3166-2']['$']) ) except KeyError: @@ -1034,7 +1054,7 @@ def _lookup_rws_arin(self, response=None, retry_count=3): for e in emails: - temp.append(e['$'].strip()) + temp.append(str(e['$']).strip()) key = '%s_emails' % poc['@description'].lower() @@ -1092,11 +1112,13 @@ def _lookup_rws_ripe(self, response=None): if attr['name'] == 'abuse-mailbox': - ripe_abuse_emails.append(attr['value'].strip()) + ripe_abuse_emails.append(str( + attr['value'] + ).strip()) elif attr['name'] == 'e-mail': - ripe_misc_emails.append(attr['value'].strip()) + ripe_misc_emails.append(str(attr['value']).strip()) elif n['type'] in ('inetnum', 'inet6num', 'route', 'route6'): @@ -1106,7 +1128,7 @@ def _lookup_rws_ripe(self, response=None): if attr['name'] in ('inetnum', 'inet6num'): - ipr = attr['value'].strip() + ipr = str(attr['value']).strip() ip_range = ipr.split(' - ') try: @@ -1115,25 +1137,20 @@ def _lookup_rws_ripe(self, response=None): addrs = [] addrs.extend( - ipaddress.summarize_address_range( - ipaddress.ip_address( - ip_range[0]), - ipaddress.ip_address( - ip_range[1]) + summarize_address_range( + ip_address(ip_range[0]), + ip_address(ip_range[1]) ) ) cidr = ', '.join( [i.__str__() - for i in ipaddress. - collapse_addresses(addrs)] + for i in collapse_addresses(addrs)] ) else: - cidr = ipaddress.ip_network( - ip_range[0] - ).__str__() + cidr = ip_network(ip_range[0]).__str__() net['cidr'] = cidr @@ -1143,14 +1160,13 @@ def _lookup_rws_ripe(self, response=None): elif attr['name'] in ('route', 'route6'): - ipr = attr['value'].strip() + ipr = str(attr['value']).strip() ip_ranges = ipr.split(', ') try: net['cidr'] = ', '.join( - ipaddress.ip_network(r).__str__() - for r in ip_ranges + ip_network(r).__str__() for r in ip_ranges ) except ValueError: @@ -1159,35 +1175,35 @@ def _lookup_rws_ripe(self, response=None): elif attr['name'] == 'netname': - net['name'] = attr['value'].strip() + net['name'] = str(attr['value']).strip() elif attr['name'] == 'descr': if net['description'] is not None: net['description'] += '\n%s' % ( - attr['value'].strip() + str(attr['value']).strip() ) else: - net['description'] = attr['value'].strip() + net['description'] = str(attr['value']).strip() elif attr['name'] == 'country': - net['country'] = attr['value'].strip() + net['country'] = str(attr['value']).strip().upper() elif attr['name'] == 'address': if net['address'] is not None: net['address'] += '\n%s' % ( - attr['value'].strip() + str(attr['value']).strip() ) else: - net['address'] = attr['value'].strip() + net['address'] = str(attr['value']).strip() nets.append(net) @@ -1235,13 +1251,12 @@ def _lookup_rws_apnic(self, response=None): try: - addrs.extend(ipaddress.summarize_address_range( - ipaddress.ip_address(response['startAddress'].strip()), - ipaddress.ip_address(response['endAddress'].strip()))) + addrs.extend(summarize_address_range( + ip_address(response['startAddress'].strip()), + ip_address(response['endAddress'].strip()))) net['cidr'] = ', '.join( - [i.__str__() - for i in ipaddress.collapse_addresses(addrs)] + [i.__str__() for i in collapse_addresses(addrs)] ) except (KeyError, ValueError, TypeError): @@ -1250,7 +1265,7 @@ def _lookup_rws_apnic(self, response=None): try: - net['country'] = response['country'].strip() + net['country'] = str(response['country']).strip().upper() except KeyError: @@ -1274,11 +1289,11 @@ def _lookup_rws_apnic(self, response=None): if ev['eventAction'] == 'registration': - net['created'] = ev['eventDate'].strip() + net['created'] = str(ev['eventDate']).strip() elif ev['eventAction'] == 'last changed': - net['updated'] = ev['eventDate'].strip() + net['updated'] = str(ev['eventDate']).strip() except (KeyError, ValueError): @@ -1306,13 +1321,13 @@ def _lookup_rws_apnic(self, response=None): if 'administrative' in en['roles'] and t[0] == 'fn': - net['name'] = t[3].strip() + net['name'] = str(t[3]).strip() elif 'administrative' in en['roles'] and t[0] == 'adr': try: - net['address'] = t[1]['label'].strip() + net['address'] = str(t[1]['label']).strip() except KeyError: @@ -1339,11 +1354,11 @@ def _lookup_rws_apnic(self, response=None): if net[key] is not None: - net[key] += '\n%s' % t[3].strip() + net[key] += '\n%s' % str(t[3]).strip() else: - net[key] = t[3].strip() + net[key] = str(t[3]).strip() except (KeyError, IndexError): @@ -1367,7 +1382,7 @@ def _lookup_rws_apnic(self, response=None): if rem['title'] == 'description': - net['description'] = '\n'.join(rem['description']) + net['description'] = str('\n'.join(rem['description'])) except (KeyError, IndexError): @@ -1395,13 +1410,12 @@ def _lookup_rws_lacnic(self, response=None): try: - addrs.extend(ipaddress.summarize_address_range( - ipaddress.ip_address(response['startAddress'].strip()), - ipaddress.ip_address(response['endAddress'].strip()))) + addrs.extend(summarize_address_range( + ip_address(response['startAddress'].strip()), + ip_address(response['endAddress'].strip()))) net['cidr'] = ', '.join( - [i.__str__() - for i in ipaddress.collapse_addresses(addrs)] + [i.__str__() for i in collapse_addresses(addrs)] ) except (KeyError, ValueError, TypeError): @@ -1410,7 +1424,7 @@ def _lookup_rws_lacnic(self, response=None): try: - net['country'] = response['country'].strip() + net['country'] = str(response['country']).strip().upper() except KeyError: @@ -1434,7 +1448,7 @@ def _lookup_rws_lacnic(self, response=None): if ev['eventAction'] == 'registration': - tmp = ev['eventDate'].strip() + tmp = str(ev['eventDate']).strip() value = datetime.strptime( tmp, @@ -1445,7 +1459,7 @@ def _lookup_rws_lacnic(self, response=None): elif ev['eventAction'] == 'last changed': - tmp = ev['eventDate'].strip() + tmp = str(ev['eventDate']).strip() value = datetime.strptime( tmp, @@ -1482,19 +1496,19 @@ def _lookup_rws_lacnic(self, response=None): if t[0] == 'fn': - net['name'] = t[3].strip() + net['name'] = str(t[3]).strip() elif t[0] == 'org': - net['description'] = t[3][0].strip() + net['description'] = str(t[3][0]).strip() elif t[0] == 'adr': - net['address'] = t[1]['label'].strip() + net['address'] = str(t[1]['label']).strip() elif t[0] == 'email': - net['misc_emails'] = t[3].strip() + net['misc_emails'] = str(t[3]).strip() elif en['roles'][0] == 'abuse': @@ -1504,7 +1518,7 @@ def _lookup_rws_lacnic(self, response=None): if t[0] == 'email': - net['abuse_emails'] = t[3].strip() + net['abuse_emails'] = str(t[3]).strip() elif en['roles'][0] == 'tech': @@ -1514,7 +1528,7 @@ def _lookup_rws_lacnic(self, response=None): if t[0] == 'email': - net['tech_emails'] = t[3].strip() + net['tech_emails'] = str(t[3]).strip() except (KeyError, IndexError): diff --git a/ipwhois/tests/test_ipwhois.py b/ipwhois/tests/test_ipwhois.py index 1864646..769077a 100644 --- a/ipwhois/tests/test_ipwhois.py +++ b/ipwhois/tests/test_ipwhois.py @@ -5,8 +5,20 @@ class TestIPWhois(unittest.TestCase): + if not hasattr(unittest.TestCase, 'assertIsInstance'): + def assertIsInstance(self, obj, cls, msg=None): + if not isinstance(obj, cls): + self.fail(self._formatMessage( + msg, + '%s is not an instance of %r' % (repr(obj), cls) + )) + def test_ip_invalid(self): - from ipaddress import AddressValueError + try: + from ipaddress import AddressValueError + except ImportError: + from ipaddr import AddressValueError + self.assertRaises(ValueError, IPWhois, '192.168.0.256') self.assertRaises(AddressValueError, IPWhois, 1234) @@ -25,7 +37,11 @@ def test_timeout(self): self.assertIsInstance(result.timeout, int) def test_proxy_opener(self): - from urllib.request import OpenerDirector + try: + from urllib.request import OpenerDirector + except ImportError: + from urllib2 import OpenerDirector + result = IPWhois('74.125.225.229') self.assertIsInstance(result.opener, OpenerDirector) @@ -114,7 +130,10 @@ def test_lookup(self): self.fail('Unexpected exception raised: %r' % e) def test_lookup_rws(self): - from urllib import request + try: + from urllib.request import ProxyHandler, build_opener + except ImportError: + from urllib2 import ProxyHandler, build_opener ips = [ '74.125.225.229', # ARIN @@ -141,7 +160,7 @@ def test_lookup_rws(self): except Exception as e: self.fail('Unexpected exception raised: %r' % e) - handler = request.ProxyHandler({'http': 'http://0.0.0.0:80/'}) - opener = request.build_opener(handler) + handler = ProxyHandler({'http': 'http://0.0.0.0:80/'}) + opener = build_opener(handler) result = IPWhois('74.125.225.229', 0, opener) self.assertRaises(WhoisLookupError, result.lookup_rws) diff --git a/ipwhois/tests/test_utils.py b/ipwhois/tests/test_utils.py index 8a8dc54..ac3e1f2 100644 --- a/ipwhois/tests/test_utils.py +++ b/ipwhois/tests/test_utils.py @@ -4,13 +4,25 @@ class TestFunctions(unittest.TestCase): + if not hasattr(unittest.TestCase, 'assertIsInstance'): + def assertIsInstance(self, obj, cls, msg=None): + if not isinstance(obj, cls): + self.fail(self._formatMessage( + msg, + '%s is not an instance of %r' % (repr(obj), cls) + )) + def test_get_countries(self): countries = get_countries() self.assertIsInstance(countries, dict) self.assertEqual(countries['US'], 'United States') def test_ipv4_is_defined(self): - from ipaddress import AddressValueError + try: + from ipaddress import AddressValueError + except ImportError: + from ipaddr import AddressValueError + self.assertRaises(ValueError, ipv4_is_defined, '192.168.0.256') self.assertRaises(AddressValueError, ipv4_is_defined, 1234) self.assertEquals(ipv4_is_defined('192.168.0.1'), @@ -18,7 +30,11 @@ def test_ipv4_is_defined(self): self.assertEquals(ipv4_is_defined('74.125.225.229'), (False, '', '')) def test_ipv6_is_defined(self): - from ipaddress import AddressValueError + try: + from ipaddress import AddressValueError + except ImportError: + from ipaddr import AddressValueError + self.assertRaises(ValueError, ipv6_is_defined, '2001:4860:4860::8888::1234') self.assertRaises(AddressValueError, ipv6_is_defined, 1234) diff --git a/ipwhois/utils.py b/ipwhois/utils.py index aaa60bd..a6fcb13 100644 --- a/ipwhois/utils.py +++ b/ipwhois/utils.py @@ -22,7 +22,10 @@ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. -import ipaddress +try: + import ipaddress +except ImportError: + import ipaddr as ipaddress from xml.dom.minidom import parseString from os import path import sys diff --git a/setup.py b/setup.py index 8064b90..151dc9b 100644 --- a/setup.py +++ b/setup.py @@ -2,6 +2,7 @@ from distutils.core import setup from ipwhois import __version__ +import sys NAME = 'ipwhois' VERSION = __version__ @@ -40,6 +41,10 @@ "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", + "Programming Language :: Python :: 2", + "Programming Language :: Python :: 2.6", + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.3", "Topic :: Internet", "Topic :: Software Development", @@ -49,9 +54,14 @@ PACKAGE_DATA = {'ipwhois': ['data/*.xml']} -INSTALL_REQUIRES = [ - "dnspython3" -] +INSTALL_REQUIRES = [] +if sys.version_info >= (3,): + INSTALL_REQUIRES.append("dnspython3") +else: + INSTALL_REQUIRES.append("dnspython") + +if sys.version_info < (3, 3,): + INSTALL_REQUIRES.append("ipaddr") setup( name=NAME,