summaryrefslogtreecommitdiffstats
path: root/netaddr/core.py
diff options
context:
space:
mode:
Diffstat (limited to 'netaddr/core.py')
-rw-r--r--netaddr/core.py210
1 files changed, 210 insertions, 0 deletions
diff --git a/netaddr/core.py b/netaddr/core.py
new file mode 100644
index 0000000..0fdbb40
--- /dev/null
+++ b/netaddr/core.py
@@ -0,0 +1,210 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 2008 by David P. D. Moss. All rights reserved.
+#
+# Released under the BSD license. See the LICENSE file for details.
+#-----------------------------------------------------------------------------
+"""Common code shared between various netaddr sub modules"""
+
+import sys as _sys
+import pprint as _pprint
+
+from netaddr.compat import _callable, _iter_dict_keys
+
+#: True if platform is natively big endian, False otherwise.
+BIG_ENDIAN_PLATFORM = _sys.byteorder == 'big'
+
+#: Use inet_pton() semantics instead of inet_aton() when parsing IPv4.
+P = INET_PTON = 1
+
+#: Remove any preceding zeros from IPv4 address octets before parsing.
+Z = ZEROFILL = 2
+
+#: Remove any host bits found to the right of an applied CIDR prefix.
+N = NOHOST = 4
+
+#: Use legacy ``inet_aton()`` semantics when parsing IPv4.
+INET_ATON = 8
+
+#-----------------------------------------------------------------------------
+# Custom exceptions.
+#-----------------------------------------------------------------------------
+class AddrFormatError(Exception):
+ """
+ An Exception indicating a network address is not correctly formatted.
+ """
+ pass
+
+
+class AddrConversionError(Exception):
+ """
+ An Exception indicating a failure to convert between address types or
+ notations.
+ """
+ pass
+
+
+class NotRegisteredError(Exception):
+ """
+ An Exception indicating that an OUI or IAB was not found in the IEEE
+ Registry.
+ """
+ pass
+
+
+try:
+ a = 42
+ a.bit_length()
+ # No exception, must be Python 2.7 or 3.1+ -> can use bit_length()
+ del a
+ def num_bits(int_val):
+ """
+ :param int_val: an unsigned integer.
+
+ :return: the minimum number of bits needed to represent value provided.
+ """
+ return int_val.bit_length()
+except AttributeError:
+ # a.bit_length() excepted, must be an older Python version.
+ def num_bits(int_val):
+ """
+ :param int_val: an unsigned integer.
+
+ :return: the minimum number of bits needed to represent value provided.
+ """
+ numbits = 0
+ while int_val:
+ numbits += 1
+ int_val >>= 1
+ return numbits
+
+
+class Subscriber(object):
+ """
+ An abstract class defining the interface expected by a Publisher.
+ """
+
+ def update(self, data):
+ """
+ A callback method used by a Publisher to notify this Subscriber about
+ updates.
+
+ :param data: a Python object containing data provided by Publisher.
+ """
+ raise NotImplementedError('cannot invoke virtual method!')
+
+
+class PrettyPrinter(Subscriber):
+ """
+ A concrete Subscriber that employs the pprint in the standard library to
+ format all data from updates received, writing them to a file-like
+ object.
+
+ Useful as a debugging aid.
+ """
+
+ def __init__(self, fh=_sys.stdout, write_eol=True):
+ """
+ Constructor.
+
+ :param fh: a file-like object to write updates to.
+ Default: sys.stdout.
+
+
+ :param write_eol: if ``True`` this object will write newlines to
+ output, if ``False`` it will not.
+ """
+ self.fh = fh
+ self.write_eol = write_eol
+
+ def update(self, data):
+ """
+ A callback method used by a Publisher to notify this Subscriber about
+ updates.
+
+ :param data: a Python object containing data provided by Publisher.
+ """
+ self.fh.write(_pprint.pformat(data))
+ if self.write_eol:
+ self.fh.write("\n")
+
+
+class Publisher(object):
+ """
+ A 'push' Publisher that maintains a list of Subscriber objects notifying
+ them of state changes by passing them update data when it encounter events
+ of interest.
+ """
+
+ def __init__(self):
+ """Constructor"""
+ self.subscribers = []
+
+ def attach(self, subscriber):
+ """
+ Add a new subscriber.
+
+ :param subscriber: a new object that implements the Subscriber object
+ interface.
+ """
+ if hasattr(subscriber, 'update') and _callable(subscriber.update):
+ if subscriber not in self.subscribers:
+ self.subscribers.append(subscriber)
+ else:
+ raise TypeError('%r does not support required interface!' % subscriber)
+
+ def detach(self, subscriber):
+ """
+ Remove an existing subscriber.
+
+ :param subscriber: a new object that implements the Subscriber object
+ interface.
+ """
+ try:
+ self.subscribers.remove(subscriber)
+ except ValueError:
+ pass
+
+ def notify(self, data):
+ """
+ Send update data to to all registered Subscribers.
+
+ :param data: the data to be passed to each registered Subscriber.
+ """
+ for subscriber in self.subscribers:
+ subscriber.update(data)
+
+
+class DictDotLookup(object):
+ """
+ Creates objects that behave much like a dictionaries, but allow nested
+ key access using object '.' (dot) lookups.
+
+ Recipe 576586: Dot-style nested lookups over dictionary based data
+ structures - http://code.activestate.com/recipes/576586/
+
+ """
+
+ def __init__(self, d):
+ for k in d:
+ if isinstance(d[k], dict):
+ self.__dict__[k] = DictDotLookup(d[k])
+ elif isinstance(d[k], (list, tuple)):
+ l = []
+ for v in d[k]:
+ if isinstance(v, dict):
+ l.append(DictDotLookup(v))
+ else:
+ l.append(v)
+ self.__dict__[k] = l
+ else:
+ self.__dict__[k] = d[k]
+
+ def __getitem__(self, name):
+ if name in self.__dict__:
+ return self.__dict__[name]
+
+ def __iter__(self):
+ return _iter_dict_keys(self.__dict__)
+
+ def __repr__(self):
+ return _pprint.pformat(self.__dict__)