diff options
author | Jakub Stasiak <jakub@stasiak.at> | 2020-06-17 19:05:45 +0200 |
---|---|---|
committer | Jakub Stasiak <jakub@stasiak.at> | 2020-06-17 19:05:45 +0200 |
commit | 297ac7081f76224fb194a7b5350e6d129c328eb4 (patch) | |
tree | 33f20c1c7b29bac1026f76be6f9247f8a5be529c | |
parent | 036fc2f39ed55aa0a4e709473bb6d5f7d3b2ef4a (diff) | |
parent | 5b2807ff91640c959dc358334f626cea0e28778c (diff) | |
download | netaddr-next-master.tar.gz |
Merge branch 'rel-0.7.x'next-master
-rw-r--r-- | .gitattributes | 2 | ||||
-rw-r--r-- | .github/workflows/ci.yml | 24 | ||||
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | README.md | 1 | ||||
-rw-r--r-- | circle.yml | 12 | ||||
-rwxr-xr-x | netaddr/cli.py | 42 | ||||
-rw-r--r-- | netaddr/compat.py | 4 | ||||
-rw-r--r-- | netaddr/eui/__init__.py | 26 | ||||
-rwxr-xr-x | netaddr/eui/ieee.py | 40 | ||||
-rw-r--r-- | netaddr/fbsocket.py | 2 | ||||
-rw-r--r-- | netaddr/ip/__init__.py | 16 | ||||
-rw-r--r-- | netaddr/ip/glob.py | 6 | ||||
-rwxr-xr-x | netaddr/ip/iana.py | 17 | ||||
-rw-r--r-- | netaddr/ip/nmap.py | 10 | ||||
-rw-r--r-- | netaddr/ip/rfc1924.py | 2 | ||||
-rw-r--r-- | netaddr/strategy/__init__.py | 10 | ||||
-rw-r--r-- | netaddr/strategy/eui48.py | 6 | ||||
-rw-r--r-- | netaddr/strategy/eui64.py | 2 | ||||
-rw-r--r-- | netaddr/strategy/ipv4.py | 8 | ||||
-rw-r--r-- | netaddr/strategy/ipv6.py | 4 | ||||
-rw-r--r-- | netaddr/tests/eui/test_ieee_parsers.py | 13 | ||||
-rw-r--r-- | netaddr/tests/ip/test_platform_osx.py | 10 | ||||
-rw-r--r-- | netaddr/tests/strategy/test_ipv6_strategy.py | 13 | ||||
-rwxr-xr-x | netaddr/tools/netaddr | 37 | ||||
-rw-r--r-- | setup.py | 29 |
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 @@ -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 @@ -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() @@ -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) |