summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Stasiak <jakub@stasiak.at>2020-06-17 19:05:45 +0200
committerJakub Stasiak <jakub@stasiak.at>2020-06-17 19:05:45 +0200
commit297ac7081f76224fb194a7b5350e6d129c328eb4 (patch)
tree33f20c1c7b29bac1026f76be6f9247f8a5be529c
parent036fc2f39ed55aa0a4e709473bb6d5f7d3b2ef4a (diff)
parent5b2807ff91640c959dc358334f626cea0e28778c (diff)
downloadnetaddr-next-master.tar.gz
Merge branch 'rel-0.7.x'next-master
-rw-r--r--.gitattributes2
-rw-r--r--.github/workflows/ci.yml24
-rw-r--r--Makefile2
-rw-r--r--README.md1
-rw-r--r--circle.yml12
-rwxr-xr-xnetaddr/cli.py42
-rw-r--r--netaddr/compat.py4
-rw-r--r--netaddr/eui/__init__.py26
-rwxr-xr-xnetaddr/eui/ieee.py40
-rw-r--r--netaddr/fbsocket.py2
-rw-r--r--netaddr/ip/__init__.py16
-rw-r--r--netaddr/ip/glob.py6
-rwxr-xr-xnetaddr/ip/iana.py17
-rw-r--r--netaddr/ip/nmap.py10
-rw-r--r--netaddr/ip/rfc1924.py2
-rw-r--r--netaddr/strategy/__init__.py10
-rw-r--r--netaddr/strategy/eui48.py6
-rw-r--r--netaddr/strategy/eui64.py2
-rw-r--r--netaddr/strategy/ipv4.py8
-rw-r--r--netaddr/strategy/ipv6.py4
-rw-r--r--netaddr/tests/eui/test_ieee_parsers.py13
-rw-r--r--netaddr/tests/ip/test_platform_osx.py10
-rw-r--r--netaddr/tests/strategy/test_ipv6_strategy.py13
-rwxr-xr-xnetaddr/tools/netaddr37
-rw-r--r--setup.py29
25 files changed, 183 insertions, 155 deletions
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..6de81d8
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,2 @@
+# Tell Git not to mess with line endings when checking out on Windows, it breaks tests
+* -text
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..76c8095
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,24 @@
+name: CI
+
+on: [push, pull_request]
+
+jobs:
+ build:
+ runs-on: ${{ matrix.os }}
+ strategy:
+ matrix:
+ os: [ubuntu-latest, macos-latest, windows-latest]
+ python-version: [2.7, 3.5, 3.6, 3.7, 3.8, pypy2, pypy3]
+ steps:
+ - uses: actions/checkout@v2
+ - name: Set up Python ${{ matrix.python-version }}
+ uses: actions/setup-python@v2
+ with:
+ python-version: ${{ matrix.python-version }}
+ - name: Install dependencies
+ run: |
+ pip install --upgrade -r requirements.txt
+ pip install .
+ - name: Run tests
+ run: |
+ make test_with_junitxml
diff --git a/Makefile b/Makefile
index 2fee338..a366c00 100644
--- a/Makefile
+++ b/Makefile
@@ -68,4 +68,4 @@ test: clean
test_with_junitxml: clean
@echo 'running test suite with JUnit XML output'
- py.test -vv --junitxml=$$CI_REPORTS/junit.xml $(PWD)/netaddr/tests
+ py.test -vv --junitxml=junit.xml
diff --git a/README.md b/README.md
index 6402e56..4c0f327 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,6 @@ netaddr
A network address manipulation library for Python
-[![Circle CI](https://circleci.com/gh/drkjam/netaddr.png?style=shield)](https://circleci.com/gh/drkjam/netaddr)
[![Latest Version](https://img.shields.io/pypi/v/netaddr.svg)](https://pypi.python.org/pypi/netaddr)
Provides support for:
diff --git a/circle.yml b/circle.yml
deleted file mode 100644
index a07dd73..0000000
--- a/circle.yml
+++ /dev/null
@@ -1,12 +0,0 @@
-machine:
- python:
- version: 2.7.10
-
-test:
- override:
- - make test_with_junitxml
-
-general:
- branches:
- only:
- - rel-0.7.x
diff --git a/netaddr/cli.py b/netaddr/cli.py
new file mode 100755
index 0000000..c97eab9
--- /dev/null
+++ b/netaddr/cli.py
@@ -0,0 +1,42 @@
+#!/usr/bin/env python
+#-----------------------------------------------------------------------------
+# Copyright (c) 2008 by David P. D. Moss. All rights reserved.
+#
+# Released under the BSD license. See the LICENSE file for details.
+#-----------------------------------------------------------------------------
+"""an interactive shell for the netaddr library"""
+
+import os
+import sys
+import netaddr
+from netaddr import *
+
+# aliases to save some typing ...
+from netaddr import IPAddress as IP, IPNetwork as CIDR
+from netaddr import EUI as MAC
+
+def main():
+ argv = sys.argv[1:]
+
+ banner = "\nnetaddr shell %s - %s\n" % (netaddr.__version__, __doc__)
+ exit_msg = "\nShare and enjoy!"
+ rc_override = None
+
+ try:
+ try:
+ # ipython >= 0.11
+ from IPython.terminal.embed import InteractiveShellEmbed
+ ipshell = InteractiveShellEmbed(banner1=banner, exit_msg=exit_msg)
+ except ImportError:
+ # ipython < 0.11
+ from IPython.Shell import IPShellEmbed
+ ipshell = IPShellEmbed(argv, banner, exit_msg, rc_override)
+ except ImportError:
+ sys.stderr.write('IPython (http://ipython.scipy.org/) not found!\n')
+ sys.exit(1)
+
+ ipshell()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/netaddr/compat.py b/netaddr/compat.py
index 0fe69ee..ad80386 100644
--- a/netaddr/compat.py
+++ b/netaddr/compat.py
@@ -113,3 +113,7 @@ else:
raise RuntimeError(
'this module only supports Python 2.4.x or higher (including 3.x)!')
+try:
+ from importlib import resources as _importlib_resources
+except ImportError:
+ import importlib_resources as _importlib_resources
diff --git a/netaddr/eui/__init__.py b/netaddr/eui/__init__.py
index aa79014..c288ad3 100644
--- a/netaddr/eui/__init__.py
+++ b/netaddr/eui/__init__.py
@@ -13,7 +13,7 @@ from netaddr.strategy import eui48 as _eui48, eui64 as _eui64
from netaddr.strategy.eui48 import mac_eui48
from netaddr.strategy.eui64 import eui64_base
from netaddr.ip import IPAddress
-from netaddr.compat import _is_int, _is_str
+from netaddr.compat import _importlib_resources, _is_int, _is_str
class BaseIdentifier(object):
@@ -85,20 +85,20 @@ class OUI(BaseIdentifier):
if 0 <= oui <= 0xffffff:
self._value = oui
else:
- raise ValueError('OUI int outside expected range: %r' % oui)
+ raise ValueError('OUI int outside expected range: %r' % (oui,))
else:
- raise TypeError('unexpected OUI format: %r' % oui)
+ raise TypeError('unexpected OUI format: %r' % (oui,))
# Discover offsets.
if self._value in ieee.OUI_INDEX:
- fh = open(ieee.OUI_REGISTRY_PATH, 'rb')
+ fh = _importlib_resources.open_binary(__package__, 'oui.txt')
for (offset, size) in ieee.OUI_INDEX[self._value]:
fh.seek(offset)
data = fh.read(size).decode('UTF-8')
self._parse_data(data, offset, size)
fh.close()
else:
- raise NotRegisteredError('OUI %r not registered!' % oui)
+ raise NotRegisteredError('OUI %r not registered!' % (oui,))
def __eq__(self, other):
if not isinstance(other, OUI):
@@ -252,11 +252,11 @@ class IAB(BaseIdentifier):
iab_int, user_int = self.split_iab_mac(iab, strict=strict)
self._value = iab_int
else:
- raise TypeError('unexpected IAB format: %r!' % iab)
+ raise TypeError('unexpected IAB format: %r!' % (iab,))
# Discover offsets.
if self._value in ieee.IAB_INDEX:
- fh = open(ieee.IAB_REGISTRY_PATH, 'rb')
+ fh = _importlib_resources.open_binary(__package__, 'iab.txt')
(offset, size) = ieee.IAB_INDEX[self._value][0]
self.record['offset'] = offset
self.record['size'] = size
@@ -265,7 +265,7 @@ class IAB(BaseIdentifier):
self._parse_data(data, offset, size)
fh.close()
else:
- raise NotRegisteredError('IAB %r not unregistered!' % iab)
+ raise NotRegisteredError('IAB %r not unregistered!' % (iab,))
def __eq__(self, other):
if not isinstance(other, IAB):
@@ -408,7 +408,7 @@ class EUI(BaseIdentifier):
self._module = _eui64
else:
raise ValueError('unpickling failed for object state: %s' \
- % str(state))
+ % (state,))
self.dialect = dialect
@@ -434,7 +434,7 @@ class EUI(BaseIdentifier):
if self._module is None:
raise AddrFormatError('failed to detect EUI version: %r'
- % value)
+ % (value,))
else:
# EUI version is explicit.
if _is_str(value):
@@ -447,7 +447,7 @@ class EUI(BaseIdentifier):
if 0 <= int(value) <= self._module.max_int:
self._value = int(value)
else:
- raise AddrFormatError('bad address format: %r' % value)
+ raise AddrFormatError('bad address format: %r' % (value,))
value = property(_get_value, _set_value, None,
'a positive integer representing the value of this EUI indentifier.')
@@ -522,7 +522,7 @@ class EUI(BaseIdentifier):
words = self._module.int_to_words(self._value, self._dialect)
return [words[i] for i in range(*idx.indices(len(words)))]
else:
- raise TypeError('unsupported type %r!' % idx)
+ raise TypeError('unsupported type %r!' % (idx,))
def __setitem__(self, idx, value):
"""Set the value of the word referenced by index in this address"""
@@ -534,7 +534,7 @@ class EUI(BaseIdentifier):
raise TypeError('index not an integer!')
if not 0 <= idx <= (self._dialect.num_words - 1):
- raise IndexError('index %d outside address type boundary!' % idx)
+ raise IndexError('index %d outside address type boundary!' % (idx,))
if not _is_int(value):
raise TypeError('value not an integer!')
diff --git a/netaddr/eui/ieee.py b/netaddr/eui/ieee.py
index 36380f6..3e66d55 100755
--- a/netaddr/eui/ieee.py
+++ b/netaddr/eui/ieee.py
@@ -35,24 +35,13 @@ More details can be found at the following URLs :-
import os.path as _path
import csv as _csv
-from netaddr.compat import _bytes_type
+from netaddr.compat import _bytes_type, _importlib_resources
from netaddr.core import Subscriber, Publisher
-#: Path to local copy of IEEE OUI Registry data file.
-OUI_REGISTRY_PATH = _path.join(_path.dirname(__file__), 'oui.txt')
-#: Path to netaddr OUI index file.
-OUI_INDEX_PATH = _path.join(_path.dirname(__file__), 'oui.idx')
-
#: OUI index lookup dictionary.
OUI_INDEX = {}
-#: Path to local copy of IEEE IAB Registry data file.
-IAB_REGISTRY_PATH = _path.join(_path.dirname(__file__), 'iab.txt')
-
-#: Path to netaddr IAB index file.
-IAB_INDEX_PATH = _path.join(_path.dirname(__file__), 'iab.idx')
-
#: IAB index lookup dictionary.
IAB_INDEX = {}
@@ -258,22 +247,29 @@ class IABIndexParser(Publisher):
self.notify(record)
-def create_index_from_registry(registry_path, index_path, parser):
+def create_index_from_registry(registry_fh, index_path, parser):
"""Generate an index files from the IEEE registry file."""
- oui_parser = parser(registry_path)
+ oui_parser = parser(registry_fh)
oui_parser.attach(FileIndexer(index_path))
oui_parser.parse()
def create_indices():
"""Create indices for OUI and IAB file based lookups"""
- create_index_from_registry(OUI_REGISTRY_PATH, OUI_INDEX_PATH, OUIIndexParser)
- create_index_from_registry(IAB_REGISTRY_PATH, IAB_INDEX_PATH, IABIndexParser)
-
-
-def load_index(index, index_path):
+ create_index_from_registry(
+ _path.join(_path.dirname(__file__), 'oui.txt'),
+ _path.join(_path.dirname(__file__), 'oui.idx'),
+ OUIIndexParser,
+ )
+ create_index_from_registry(
+ _path.join(_path.dirname(__file__), 'iab.txt'),
+ _path.join(_path.dirname(__file__), 'iab.idx'),
+ IABIndexParser,
+ )
+
+
+def load_index(index, fp):
"""Load index from file into index data structure."""
- fp = open(index_path, 'rb')
try:
for row in _csv.reader([x.decode('UTF-8') for x in fp]):
(key, offset, size) = [int(_) for _ in row]
@@ -285,8 +281,8 @@ def load_index(index, index_path):
def load_indices():
"""Load OUI and IAB lookup indices into memory"""
- load_index(OUI_INDEX, OUI_INDEX_PATH)
- load_index(IAB_INDEX, IAB_INDEX_PATH)
+ load_index(OUI_INDEX, _importlib_resources.open_binary(__package__, 'oui.idx'))
+ load_index(IAB_INDEX, _importlib_resources.open_binary(__package__, 'iab.idx'))
if __name__ == '__main__':
diff --git a/netaddr/fbsocket.py b/netaddr/fbsocket.py
index 05578b7..0e376b3 100644
--- a/netaddr/fbsocket.py
+++ b/netaddr/fbsocket.py
@@ -18,7 +18,7 @@ def inet_ntoa(packed_ip):
Convert an IP address from 32-bit packed binary format to string format.
"""
if not _is_str(packed_ip):
- raise TypeError('string type expected, not %s' % str(type(packed_ip)))
+ raise TypeError('string type expected, not %s' % type(packed_ip))
if len(packed_ip) != 4:
raise ValueError('invalid length of packed IP address string')
diff --git a/netaddr/ip/__init__.py b/netaddr/ip/__init__.py
index ecf72d0..cb43012 100644
--- a/netaddr/ip/__init__.py
+++ b/netaddr/ip/__init__.py
@@ -316,7 +316,7 @@ class IPAddress(BaseIP):
if 0 <= int(addr) <= self._module.max_int:
self._value = int(addr)
else:
- raise AddrFormatError('bad address format: %r' % addr)
+ raise AddrFormatError('bad address format: %r' % (addr,))
def __getstate__(self):
""":returns: Pickled state of an `IPAddress` object."""
@@ -935,7 +935,7 @@ class IPNetwork(BaseIP, IPListMixin):
pass
if value is None:
- raise AddrFormatError('invalid IPNetwork %s' % addr)
+ raise AddrFormatError('invalid IPNetwork %s' % (addr,))
self._value = value
self._prefixlen = prefixlen
@@ -960,13 +960,13 @@ class IPNetwork(BaseIP, IPListMixin):
self._module = _ipv6
else:
raise ValueError('unpickling failed for object state %s' \
- % str(state))
+ % (state,))
if 0 <= prefixlen <= self._module.width:
self._prefixlen = prefixlen
else:
raise ValueError('unpickling failed for object state %s' \
- % str(state))
+ % (state,))
def _set_prefixlen(self, value):
if not isinstance(value, _int_type):
@@ -1505,7 +1505,7 @@ def cidr_abbrev_to_verbose(abbrev_cidr):
try:
if not 0 <= int(prefix) <= 32:
raise ValueError('prefixlen in address %r out of range' \
- ' for IPv4!' % abbrev_cidr)
+ ' for IPv4!' % (abbrev_cidr,))
except ValueError:
return abbrev_cidr
else:
@@ -1783,7 +1783,7 @@ def smallest_matching_cidr(ip, cidrs):
if not hasattr(cidrs, '__iter__'):
raise TypeError('IP address/subnet sequence expected, not %r!'
- % cidrs)
+ % (cidrs,))
ip = IPAddress(ip)
for cidr in sorted([IPNetwork(cidr) for cidr in cidrs]):
@@ -1812,7 +1812,7 @@ def largest_matching_cidr(ip, cidrs):
if not hasattr(cidrs, '__iter__'):
raise TypeError('IP address/subnet sequence expected, not %r!'
- % cidrs)
+ % (cidrs,))
ip = IPAddress(ip)
for cidr in sorted([IPNetwork(cidr) for cidr in cidrs]):
@@ -1839,7 +1839,7 @@ def all_matching_cidrs(ip, cidrs):
if not hasattr(cidrs, '__iter__'):
raise TypeError('IP address/subnet sequence expected, not %r!'
- % cidrs)
+ % (cidrs,))
ip = IPAddress(ip)
for cidr in sorted([IPNetwork(cidr) for cidr in cidrs]):
diff --git a/netaddr/ip/glob.py b/netaddr/ip/glob.py
index e94fcbc..ed43b1b 100644
--- a/netaddr/ip/glob.py
+++ b/netaddr/ip/glob.py
@@ -77,7 +77,7 @@ def glob_to_iptuple(ipglob):
:return: a tuple contain lower and upper bound IP objects.
"""
if not valid_glob(ipglob):
- raise AddrFormatError('not a recognised IP glob range: %r!' % ipglob)
+ raise AddrFormatError('not a recognised IP glob range: %r!' % (ipglob,))
start_tokens = []
end_tokens = []
@@ -107,7 +107,7 @@ def glob_to_iprange(ipglob):
:return: an IPRange object.
"""
if not valid_glob(ipglob):
- raise AddrFormatError('not a recognised IP glob range: %r!' % ipglob)
+ raise AddrFormatError('not a recognised IP glob range: %r!' % (ipglob,))
start_tokens = []
end_tokens = []
@@ -242,7 +242,7 @@ class IPGlob(IPRange):
A few basic rules also apply :
- 1. ``x`` must always be greater than ``y``, therefore :
+ 1. ``x`` must always be less than ``y``, therefore :
- ``x`` can only be ``0`` through ``254``
- ``y`` can only be ``1`` through ``255``
diff --git a/netaddr/ip/iana.py b/netaddr/ip/iana.py
index f8945e6..116c8ff 100755
--- a/netaddr/ip/iana.py
+++ b/netaddr/ip/iana.py
@@ -29,13 +29,12 @@ More details can be found at the following URLs :-
- IEEE Protocols Information Home Page - http://www.iana.org/protocols/
"""
-import os.path as _path
import sys as _sys
from xml.sax import make_parser, handler
from netaddr.core import Publisher, Subscriber
from netaddr.ip import IPAddress, IPNetwork, IPRange, cidr_abbrev_to_verbose
-from netaddr.compat import _dict_items, _callable
+from netaddr.compat import _dict_items, _callable, _importlib_resources
@@ -362,21 +361,21 @@ def load_info():
Parse and load internal IANA data lookups with the latest information from
data files.
"""
- PATH = _path.dirname(__file__)
-
- ipv4 = IPv4Parser(open(_path.join(PATH, 'ipv4-address-space.xml')))
+ ipv4 = IPv4Parser(_importlib_resources.open_binary(__package__, 'ipv4-address-space.xml'))
ipv4.attach(DictUpdater(IANA_INFO['IPv4'], 'IPv4', 'prefix'))
ipv4.parse()
- ipv6 = IPv6Parser(open(_path.join(PATH, 'ipv6-address-space.xml')))
+ ipv6 = IPv6Parser(_importlib_resources.open_binary(__package__, 'ipv6-address-space.xml'))
ipv6.attach(DictUpdater(IANA_INFO['IPv6'], 'IPv6', 'prefix'))
ipv6.parse()
- ipv6ua = IPv6UnicastParser(open(_path.join(PATH, 'ipv6-unicast-address-assignments.xml')))
+ ipv6ua = IPv6UnicastParser(
+ _importlib_resources.open_binary(__package__, 'ipv6-unicast-address-assignments.xml'),
+ )
ipv6ua.attach(DictUpdater(IANA_INFO['IPv6_unicast'], 'IPv6_unicast', 'prefix'))
ipv6ua.parse()
- mcast = MulticastParser(open(_path.join(PATH, 'multicast-addresses.xml')))
+ mcast = MulticastParser(_importlib_resources.open_binary(__package__, 'multicast-addresses.xml'))
mcast.attach(DictUpdater(IANA_INFO['multicast'], 'multicast', 'address'))
mcast.parse()
@@ -407,7 +406,7 @@ def _within_bounds(ip, ip_range):
# IP address.
return ip == ip_range
- raise Exception('Unsupported IP range or address: %r!' % ip_range)
+ raise Exception('Unsupported IP range or address: %r!' % (ip_range,))
def query(ip_addr):
diff --git a/netaddr/ip/nmap.py b/netaddr/ip/nmap.py
index 4aa6775..bacc577 100644
--- a/netaddr/ip/nmap.py
+++ b/netaddr/ip/nmap.py
@@ -31,15 +31,15 @@ def _nmap_octet_target_values(spec):
low = int(left)
high = int(right)
if not ((0 <= low <= 255) and (0 <= high <= 255)):
- raise ValueError('octet value overflow for spec %s!' % spec)
+ raise ValueError('octet value overflow for spec %s!' % (spec,))
if low > high:
- raise ValueError('left side of hyphen must be <= right %r' % element)
+ raise ValueError('left side of hyphen must be <= right %r' % (element,))
for octet in _iter_range(low, high + 1):
values.add(octet)
else:
octet = int(element)
if not (0 <= octet <= 255):
- raise ValueError('octet value overflow for spec %s!' % spec)
+ raise ValueError('octet value overflow for spec %s!' % (spec,))
values.add(octet)
return sorted(values)
@@ -57,7 +57,7 @@ def _generate_nmap_octet_ranges(nmap_target_spec):
tokens = nmap_target_spec.split('.')
if len(tokens) != 4:
- raise AddrFormatError('invalid nmap range: %s' % nmap_target_spec)
+ raise AddrFormatError('invalid nmap range: %s' % (nmap_target_spec,))
return (_nmap_octet_target_values(tokens[0]),
_nmap_octet_target_values(tokens[1]),
@@ -69,7 +69,7 @@ def _parse_nmap_target_spec(target_spec):
if '/' in target_spec:
_, prefix = target_spec.split('/', 1)
if not (0 < int(prefix) < 33):
- raise AddrFormatError('CIDR prefix expected, not %s' % prefix)
+ raise AddrFormatError('CIDR prefix expected, not %s' % (prefix,))
net = IPNetwork(target_spec)
if net.version != 4:
raise AddrFormatError('CIDR only support for IPv4!')
diff --git a/netaddr/ip/rfc1924.py b/netaddr/ip/rfc1924.py
index c4f0f9c..54fb96c 100644
--- a/netaddr/ip/rfc1924.py
+++ b/netaddr/ip/rfc1924.py
@@ -49,7 +49,7 @@ def base85_to_ipv6(addr):
tokens = list(addr)
if len(tokens) != 20:
- raise AddrFormatError('Invalid base 85 IPv6 address: %r' % addr)
+ raise AddrFormatError('Invalid base 85 IPv6 address: %r' % (addr,))
result = 0
for i, num in enumerate(reversed(tokens)):
diff --git a/netaddr/strategy/__init__.py b/netaddr/strategy/__init__.py
index 31ae431..7b5861d 100644
--- a/netaddr/strategy/__init__.py
+++ b/netaddr/strategy/__init__.py
@@ -95,7 +95,7 @@ def words_to_int(words, word_size, num_words):
by word sequence.
"""
if not valid_words(words, word_size, num_words):
- raise ValueError('invalid integer word sequence: %r!' % words)
+ raise ValueError('invalid integer word sequence: %r!' % (words,))
int_val = 0
for i, num in enumerate(reversed(words)):
@@ -152,7 +152,7 @@ def bits_to_int(bits, width, word_sep=''):
by network address in readable binary form.
"""
if not valid_bits(bits, width, word_sep):
- raise ValueError('invalid readable binary string: %r!' % bits)
+ raise ValueError('invalid readable binary string: %r!' % (bits,))
if word_sep != '':
bits = bits.replace(word_sep, '')
@@ -189,7 +189,7 @@ def int_to_bits(int_val, word_size, num_words, word_sep=''):
if word_sep != '':
# Check custom separator.
if not _is_str(word_sep):
- raise ValueError('word separator is not a string: %r!' % word_sep)
+ raise ValueError('word separator is not a string: %r!' % (word_sep,))
return word_sep.join(bit_words)
@@ -252,7 +252,7 @@ def int_to_bin(int_val, width):
bin_val = '0b' + _re.sub(r'^[0]+([01]+)$', r'\1', ''.join(bin_tokens))
if len(bin_val[2:]) > width:
- raise IndexError('binary string out of bounds: %s!' % bin_val)
+ raise IndexError('binary string out of bounds: %s!' % (bin_val,))
return bin_val
@@ -268,6 +268,6 @@ def bin_to_int(bin_val, width):
by Python binary string format.
"""
if not valid_bin(bin_val, width):
- raise ValueError('not a valid Python binary string: %r!' % bin_val)
+ raise ValueError('not a valid Python binary string: %r!' % (bin_val,))
return int(bin_val.replace('0b', ''), 2)
diff --git a/netaddr/strategy/eui48.py b/netaddr/strategy/eui48.py
index 209c950..5685e34 100644
--- a/netaddr/strategy/eui48.py
+++ b/netaddr/strategy/eui48.py
@@ -173,9 +173,9 @@ def str_to_int(addr):
words = (match_result[0],)
break
if not found_match:
- raise AddrFormatError('%r is not a supported MAC format!' % addr)
+ raise AddrFormatError('%r is not a supported MAC format!' % (addr,))
else:
- raise TypeError('%r is not str() or unicode()!' % addr)
+ raise TypeError('%r is not str() or unicode()!' % (addr,))
int_val = None
@@ -192,7 +192,7 @@ def str_to_int(addr):
# 12 bytes (bare, no delimiters)
int_val = int('%012x' % int(words[0], 16), 16)
else:
- raise AddrFormatError('unexpected word count in MAC address %r!' % addr)
+ raise AddrFormatError('unexpected word count in MAC address %r!' % (addr,))
return int_val
diff --git a/netaddr/strategy/eui64.py b/netaddr/strategy/eui64.py
index 0b9ae35..f4b0ba7 100644
--- a/netaddr/strategy/eui64.py
+++ b/netaddr/strategy/eui64.py
@@ -153,7 +153,7 @@ def str_to_int(addr):
if not words:
raise TypeError
except TypeError:
- raise AddrFormatError('invalid IEEE EUI-64 identifier: %r!' % addr)
+ raise AddrFormatError('invalid IEEE EUI-64 identifier: %r!' % (addr,))
if isinstance(words, tuple):
pass
diff --git a/netaddr/strategy/ipv4.py b/netaddr/strategy/ipv4.py
index fa5e266..56c4f24 100644
--- a/netaddr/strategy/ipv4.py
+++ b/netaddr/strategy/ipv4.py
@@ -126,7 +126,7 @@ def str_to_int(addr, flags=0):
else:
return _struct.unpack('>I', _inet_aton(addr))[0]
except Exception:
- raise AddrFormatError('%r is not a valid IPv4 address string!' % addr)
+ raise AddrFormatError('%r is not a valid IPv4 address string!' % (addr,))
def int_to_str(int_val, dialect=None):
@@ -145,7 +145,7 @@ def int_to_str(int_val, dialect=None):
(int_val >> 8) & 0xff,
int_val & 0xff)
else:
- raise ValueError('%r is not a valid 32-bit unsigned integer!' % int_val)
+ raise ValueError('%r is not a valid 32-bit unsigned integer!' % (int_val,))
def int_to_arpa(int_val):
@@ -195,7 +195,7 @@ def int_to_words(int_val):
"""
if not 0 <= int_val <= max_int:
raise ValueError('%r is not a valid integer value supported by'
- 'this address type!' % int_val)
+ 'this address type!' % (int_val,))
return ( int_val >> 24,
(int_val >> 16) & 0xff,
(int_val >> 8) & 0xff,
@@ -210,7 +210,7 @@ def words_to_int(words):
by word (octet) sequence.
"""
if not valid_words(words):
- raise ValueError('%r is not a valid octet list for an IPv4 address!' % words)
+ raise ValueError('%r is not a valid octet list for an IPv4 address!' % (words,))
return _struct.unpack('>I', _struct.pack('4B', *words))[0]
diff --git a/netaddr/strategy/ipv6.py b/netaddr/strategy/ipv6.py
index eae6678..de2a935 100644
--- a/netaddr/strategy/ipv6.py
+++ b/netaddr/strategy/ipv6.py
@@ -139,7 +139,7 @@ def str_to_int(addr, flags=0):
packed_int = _inet_pton(AF_INET6, addr)
return packed_to_int(packed_int)
except Exception:
- raise AddrFormatError('%r is not a valid IPv6 address string!' % addr)
+ raise AddrFormatError('%r is not a valid IPv6 address string!' % (addr,))
def int_to_str(int_val, dialect=None):
@@ -167,7 +167,7 @@ def int_to_str(int_val, dialect=None):
tokens = [dialect.word_fmt % word for word in words]
addr = word_sep.join(tokens)
except Exception:
- raise ValueError('%r is not a valid 128-bit unsigned integer!' % int_val)
+ raise ValueError('%r is not a valid 128-bit unsigned integer!' % (int_val,))
return addr
diff --git a/netaddr/tests/eui/test_ieee_parsers.py b/netaddr/tests/eui/test_ieee_parsers.py
index 81f1faa..f14edf4 100644
--- a/netaddr/tests/eui/test_ieee_parsers.py
+++ b/netaddr/tests/eui/test_ieee_parsers.py
@@ -1,18 +1,17 @@
-import os
+import contextlib
import sys
import pytest
+from netaddr.compat import _importlib_resources
from netaddr.eui.ieee import OUIIndexParser, IABIndexParser, FileIndexer
-SAMPLE_DIR = os.path.dirname(__file__)
-
@pytest.mark.skipif(sys.version_info > (3,), reason="requires python 2.x")
def test_oui_parser_py2():
from cStringIO import StringIO
outfile = StringIO()
- with open(os.path.join(SAMPLE_DIR, 'sample_oui.txt'), 'rb') as infile:
+ with contextlib.closing(_importlib_resources.open_binary(__package__, 'sample_oui.txt')) as infile:
iab_parser = OUIIndexParser(infile)
iab_parser.attach(FileIndexer(outfile))
iab_parser.parse()
@@ -23,7 +22,7 @@ def test_oui_parser_py2():
def test_iab_parser_py2():
from cStringIO import StringIO
outfile = StringIO()
- with open(os.path.join(SAMPLE_DIR, 'sample_iab.txt'), 'rb') as infile:
+ with contextlib.closing(_importlib_resources.open_binary(__package__, 'sample_iab.txt')) as infile:
iab_parser = IABIndexParser(infile)
iab_parser.attach(FileIndexer(outfile))
iab_parser.parse()
@@ -34,7 +33,7 @@ def test_iab_parser_py2():
def test_oui_parser_py3():
from io import StringIO
outfile = StringIO()
- with open(os.path.join(SAMPLE_DIR, 'sample_oui.txt'), 'rb') as infile:
+ with contextlib.closing(_importlib_resources.open_binary(__package__, 'sample_oui.txt')) as infile:
iab_parser = OUIIndexParser(infile)
iab_parser.attach(FileIndexer(outfile))
iab_parser.parse()
@@ -45,7 +44,7 @@ def test_oui_parser_py3():
def test_iab_parser_py3():
from io import StringIO
outfile = StringIO()
- with open(os.path.join(SAMPLE_DIR, 'sample_iab.txt'), 'rb') as infile:
+ with contextlib.closing(_importlib_resources.open_binary(__package__, 'sample_iab.txt')) as infile:
iab_parser = IABIndexParser(infile)
iab_parser.attach(FileIndexer(outfile))
iab_parser.parse()
diff --git a/netaddr/tests/ip/test_platform_osx.py b/netaddr/tests/ip/test_platform_osx.py
index 264005d..c28bceb 100644
--- a/netaddr/tests/ip/test_platform_osx.py
+++ b/netaddr/tests/ip/test_platform_osx.py
@@ -1,3 +1,5 @@
+import platform
+
import pytest
from netaddr import iprange_to_cidrs, IPNetwork, IPAddress, INET_PTON, AddrFormatError
@@ -71,9 +73,13 @@ def test_ip_behaviour_osx():
IPNetwork('::255.255.255.254/128'),
]
- # inet_pton has to be different on Mac OSX *sigh*
+ # inet_pton has to be different on Mac OSX *sigh*...
assert IPAddress('010.000.000.001', flags=INET_PTON) == IPAddress('10.0.0.1')
- assert int_to_str(0xffff) == '::0.0.255.255'
+ # ...but at least Apple changed inet_ntop in Mac OS 10.15 (Catalina) so it's compatible with Linux
+ if platform.mac_ver()[0] >= '10.15':
+ assert int_to_str(0xffff) == '::ffff'
+ else:
+ assert int_to_str(0xffff) == '::0.0.255.255'
@pytest.mark.skipif('sys.platform == "darwin"')
diff --git a/netaddr/tests/strategy/test_ipv6_strategy.py b/netaddr/tests/strategy/test_ipv6_strategy.py
index 875d583..f02c8b0 100644
--- a/netaddr/tests/strategy/test_ipv6_strategy.py
+++ b/netaddr/tests/strategy/test_ipv6_strategy.py
@@ -1,3 +1,4 @@
+import platform
import sys
import pytest
@@ -135,9 +136,17 @@ def test_strategy_ipv6_mapped_and_compatible_ipv4_string_formatting():
assert ipv6.int_to_str(0xffffffff0000) == '::ffff:255.255.0.0'
assert ipv6.int_to_str(0xffffff000000) == '::ffff:255.0.0.0'
assert ipv6.int_to_str(0xffff000000) == '::ff:ff00:0'
- assert ipv6.int_to_str(0xffff00000000) == '::ffff:0.0.0.0'
assert ipv6.int_to_str(0x1ffff00000000) == '::1:ffff:0:0'
- assert ipv6.int_to_str(0xffff00000000) == '::ffff:0.0.0.0'
+ # So this is strange. Even though on Windows we get decimal notation in a lot of the addresses above,
+ # in case of 0.0.0.0 we get hex instead, unless it's Python 2, then we get decimal... unless it's
+ # actually PyPy Python 2, then we always get hex (again, only on Windows). Worth investigating, putting
+ # the conditional assert here for now to make this visibile.
+ if platform.system() == 'Windows' and (
+ platform.python_version() >= '3.0' or platform.python_implementation() == 'PyPy'
+ ):
+ assert ipv6.int_to_str(0xffff00000000) == '::ffff:0:0'
+ else:
+ assert ipv6.int_to_str(0xffff00000000) == '::ffff:0.0.0.0'
def test_strategy_ipv6_str_to_int_behaviour_legacy_mode():
diff --git a/netaddr/tools/netaddr b/netaddr/tools/netaddr
deleted file mode 100755
index b7c2642..0000000
--- a/netaddr/tools/netaddr
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/usr/bin/env python
-#-----------------------------------------------------------------------------
-# Copyright (c) 2008 by David P. D. Moss. All rights reserved.
-#
-# Released under the BSD license. See the LICENSE file for details.
-#-----------------------------------------------------------------------------
-"""an interactive shell for the netaddr library"""
-
-import os
-import sys
-import netaddr
-from netaddr import *
-
-# aliases to save some typing ...
-from netaddr import IPAddress as IP, IPNetwork as CIDR
-from netaddr import EUI as MAC
-
-argv = sys.argv[1:]
-
-banner = "\nnetaddr shell %s - %s\n" % (netaddr.__version__, __doc__)
-exit_msg = "\nShare and enjoy!"
-rc_override = None
-
-try:
- try:
- # ipython >= 0.11
- from IPython.terminal.embed import InteractiveShellEmbed
- ipshell = InteractiveShellEmbed(banner1=banner, exit_msg=exit_msg)
- except ImportError:
- # ipython < 0.11
- from IPython.Shell import IPShellEmbed
- ipshell = IPShellEmbed(argv, banner, exit_msg, rc_override)
-except ImportError:
- sys.stderr.write('IPython (http://ipython.scipy.org/) not found!\n')
- sys.exit(1)
-
-ipshell()
diff --git a/setup.py b/setup.py
index 2bd2a08..ac403dc 100644
--- a/setup.py
+++ b/setup.py
@@ -13,8 +13,6 @@ from setuptools import setup
if os.path.exists('MANIFEST'):
os.remove('MANIFEST')
-import netaddr
-
keywords = [
'Networking', 'Systems Administration', 'IANA', 'IEEE', 'CIDR', 'IP',
'IPv4', 'IPv6', 'CIDR', 'EUI', 'MAC', 'MAC-48', 'EUI-48', 'EUI-64'
@@ -102,17 +100,12 @@ classifiers = [
'Operating System :: OS Independent',
'Programming Language :: Python',
'Programming Language :: Python :: 2',
- 'Programming Language :: Python :: 2.5',
- 'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
- 'Programming Language :: Python :: 3.0',
- 'Programming Language :: Python :: 3.1',
- 'Programming Language :: Python :: 3.2',
- 'Programming Language :: Python :: 3.3',
- 'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
+ 'Programming Language :: Python :: 3.7',
+ 'Programming Language :: Python :: 3.8',
'Topic :: Communications',
'Topic :: Documentation',
'Topic :: Education',
@@ -174,14 +167,18 @@ def main():
package_data=package_data,
packages=packages,
platforms=platforms,
- scripts=['netaddr/tools/netaddr'],
+ entry_points={'console_scripts': ['netaddr = netaddr.cli:main']},
url='https://github.com/drkjam/netaddr/',
- version=netaddr.__version__,
- options={
- 'build_scripts': {
- 'executable': '/usr/bin/env python',
- },
- },
+ version=(
+ [
+ ln for ln in open(os.path.join(os.path.dirname(__file__), 'netaddr', '__init__.py'))
+ if '__version__' in ln
+ ][0]
+ .split('=')[-1]
+ .strip()
+ .strip('\'"')
+ ),
+ install_requires=['importlib-resources;python_version<"3.7"'],
)
setup(**setup_options)