macaddress
Advanced tools
+363
-332
@@ -1,4 +0,4 @@ | ||
| Metadata-Version: 1.1 | ||
| Metadata-Version: 2.1 | ||
| Name: macaddress | ||
| Version: 1.2.0 | ||
| Version: 2.0.0 | ||
| Summary: Like ``ipaddress``, but for hardware identifiers such as MAC addresses. | ||
@@ -9,332 +9,2 @@ Home-page: https://github.com/mentalisttraceur/python-macaddress | ||
| License: 0BSD | ||
| Description: macaddress | ||
| ========== | ||
| A module for handling hardware identifiers like MAC addresses. | ||
| This module makes it easy to: | ||
| 1. check if a string represents a valid MAC address, or a similar | ||
| hardware identifier like an EUI-64, OUI, etc, | ||
| 2. convert between string and binary forms of MAC addresses and | ||
| other hardware identifiers, | ||
| and so on. | ||
| Heavily inspired by the ``ipaddress`` module, but not yet quite | ||
| as featureful. | ||
| Versioning | ||
| ---------- | ||
| This library's version numbers follow the `SemVer 2.0.0 | ||
| specification <https://semver.org/spec/v2.0.0.html>`_. | ||
| Installation | ||
| ------------ | ||
| :: | ||
| pip install macaddress | ||
| Usage | ||
| ----- | ||
| Import: | ||
| .. code:: python | ||
| import macaddress | ||
| Classes are provided for common hardware identifier | ||
| types (``MAC``/``EUI48``, ``EUI64``, ``OUI``, and | ||
| so on), as well as several less common ones. Others | ||
| might be added later. You can define ones that you | ||
| need in your code with just a few lines of code. | ||
| Parse or Validate String | ||
| ~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| When only one address type is valid: | ||
| ```````````````````````````````````` | ||
| All provided classes support the standard and common formats. | ||
| For example, the ``EUI48`` and ``MAC`` classes support the | ||
| following formats: | ||
| .. code:: python | ||
| >>> macaddress.MAC('01-23-45-67-89-ab') | ||
| MAC('01-23-45-67-89-AB') | ||
| >>> macaddress.MAC('01:23:45:67:89:ab') | ||
| MAC('01-23-45-67-89-AB') | ||
| >>> macaddress.MAC('0123.4567.89ab') | ||
| MAC('01-23-45-67-89-AB') | ||
| >>> macaddress.MAC('0123456789ab') | ||
| MAC('01-23-45-67-89-AB') | ||
| You can inspect what formats a hardware address class supports | ||
| by looking at its ``formats`` attribute: | ||
| .. code:: python | ||
| >>> macaddress.OUI.formats | ||
| ('xx-xx-xx', 'xx:xx:xx', 'xxxxxx') | ||
| Each ``x`` in the format string matches one hexadecimal | ||
| "digit", and all other characters are matched literally. | ||
| If the string does not match one of the formats, a | ||
| ``ValueError`` is raised: | ||
| .. code:: python | ||
| >>> try: | ||
| ... macaddress.MAC('foo bar') | ||
| ... except ValueError as error: | ||
| ... print(error) | ||
| ... | ||
| 'foo bar' cannot be parsed as MAC | ||
| If you need to parse in a format that isn't supported, | ||
| you can define a subclass and add the format: | ||
| .. code:: python | ||
| >>> class MACAllowsTrailingDelimiters(macaddress.MAC): | ||
| ... formats = macaddress.MAC.formats + ( | ||
| ... 'xx-xx-xx-xx-xx-xx-', | ||
| ... 'xx:xx:xx:xx:xx:xx:', | ||
| ... 'xxxx.xxxx.xxxx.', | ||
| ... ) | ||
| ... | ||
| >>> MACAllowsTrailingDelimiters('01-02-03-04-05-06-') | ||
| MACAllowsTrailingDelimiters('01-02-03-04-05-06') | ||
| When multiple address types are valid: | ||
| `````````````````````````````````````` | ||
| There is also a ``parse`` function for when you have a string | ||
| which might be one of several classes: | ||
| .. code:: python | ||
| >>> from macaddress import EUI48, EUI64, MAC, OUI | ||
| >>> macaddress.parse('01:02:03', OUI, MAC) | ||
| OUI('01-02-03') | ||
| >>> macaddress.parse('01:02:03:04:05:06', OUI, MAC, EUI64) | ||
| MAC('01-02-03-04-05-06') | ||
| >>> macaddress.parse('010203040506', EUI64, EUI48) | ||
| EUI48('01-02-03-04-05-06') | ||
| >>> macaddress.parse('0102030405060708', EUI64, EUI48, OUI, MAC) | ||
| EUI64('01-02-03-04-05-06-07-08') | ||
| If the input string cannot be parsed as any of | ||
| the given classes, a ``ValueError`` is raised: | ||
| .. code:: python | ||
| >>> try: | ||
| ... macaddress.parse('01:23', MAC, OUI) | ||
| ... except ValueError as error: | ||
| ... print(error) | ||
| ... | ||
| '01:23' cannot be parsed as MAC or OUI | ||
| >>> try: | ||
| ... macaddress.parse('01:23', MAC, OUI, EUI64) | ||
| ... except ValueError as error: | ||
| ... print(error) | ||
| ... | ||
| '01:23' cannot be parsed as MAC, OUI, or EUI64 | ||
| Note that the message of the ``ValueError`` tries to be helpful | ||
| for developers, but it is not localized, nor is its exact text | ||
| part of the official public interface covered by SemVer. | ||
| Parse from Bytes | ||
| ~~~~~~~~~~~~~~~~ | ||
| All ``macaddress`` classes can be constructed from raw bytes: | ||
| .. code:: python | ||
| >>> macaddress.MAC(b'abcdef') | ||
| MAC('61-62-63-64-65-66') | ||
| >>> macaddress.OUI(b'abc') | ||
| OUI('61-62-63') | ||
| If the byte string is the wrong size, a ``ValueError`` is raised: | ||
| .. code:: python | ||
| >>> try: | ||
| ... macaddress.MAC(b'\x01\x02\x03') | ||
| ... except ValueError as error: | ||
| ... print(error) | ||
| ... | ||
| b'\x01\x02\x03' has wrong length for MAC | ||
| Parse from Integers | ||
| ~~~~~~~~~~~~~~~~~~~ | ||
| All ``macaddress`` classes can be constructed from raw integers: | ||
| .. code:: python | ||
| >>> macaddress.MAC(0x010203ffeedd) | ||
| MAC('01-02-03-FF-EE-DD') | ||
| >>> macaddress.OUI(0x010203) | ||
| OUI('01-02-03') | ||
| Note that the least-significant bit of the integer value maps | ||
| to the last bit in the address type, so the same integer has | ||
| a different meaning depending on the class you use it with: | ||
| .. code:: python | ||
| >>> macaddress.MAC(1) | ||
| MAC('00-00-00-00-00-01') | ||
| >>> macaddress.OUI(1) | ||
| OUI('00-00-01') | ||
| If the integer is too large for the hardware identifier class | ||
| that you're trying to construct, a ``ValueError`` is raised: | ||
| .. code:: python | ||
| >>> try: | ||
| ... macaddress.OUI(1_000_000_000) | ||
| ... except ValueError as error: | ||
| ... print(error) | ||
| ... | ||
| 1000000000 is too big for OUI | ||
| Get as String | ||
| ~~~~~~~~~~~~~ | ||
| .. code:: python | ||
| >>> mac = macaddress.MAC('01-02-03-0A-0B-0C') | ||
| >>> str(mac) | ||
| '01-02-03-0A-0B-0C' | ||
| >>> str(mac).replace('-', ':') | ||
| '01:02:03:0A:0B:0C' | ||
| >>> str(mac).replace('-', '') | ||
| '0102030A0B0C' | ||
| >>> str(mac).lower() | ||
| '01-02-03-0a-0b-0c' | ||
| Get as Bytes | ||
| ~~~~~~~~~~~~ | ||
| .. code:: python | ||
| >>> mac = macaddress.MAC('61-62-63-04-05-06') | ||
| >>> bytes(mac) | ||
| b'abc\x04\x05\x06' | ||
| Get as Integer | ||
| ~~~~~~~~~~~~~~ | ||
| .. code:: python | ||
| >>> mac = macaddress.MAC('01-02-03-04-05-06') | ||
| >>> int(mac) | ||
| 1108152157446 | ||
| >>> int(mac) == 0x010203040506 | ||
| True | ||
| Get the OUI | ||
| ~~~~~~~~~~~ | ||
| Most classes supplied by this module have the ``oui`` | ||
| attribute, which returns their first three bytes as | ||
| an OUI object: | ||
| .. code:: python | ||
| >>> macaddress.MAC('01:02:03:04:05:06').oui | ||
| OUI('01-02-03') | ||
| Compare | ||
| ~~~~~~~ | ||
| Equality | ||
| ```````` | ||
| All ``macaddress`` classes support equality comparisons: | ||
| .. code:: python | ||
| >>> macaddress.OUI('01-02-03') == macaddress.OUI('01:02:03') | ||
| True | ||
| >>> macaddress.OUI('01-02-03') == macaddress.OUI('ff-ee-dd') | ||
| False | ||
| >>> macaddress.OUI('01-02-03') != macaddress.CDI32('01-02-03-04') | ||
| True | ||
| >>> macaddress.OUI('01-02-03') != macaddress.CDI32('01-02-03-04').oui | ||
| False | ||
| Ordering | ||
| ```````` | ||
| All ``macaddress`` classes support total | ||
| ordering. The comparisons are designed to | ||
| intuitively sort identifiers that start | ||
| with the same bits next to each other: | ||
| .. code:: python | ||
| >>> some_values = [ | ||
| ... MAC('ff-ee-dd-01-02-03'), | ||
| ... MAC('ff-ee-00-99-88-77'), | ||
| ... MAC('ff-ee-dd-01-02-04'), | ||
| ... OUI('ff-ee-dd'), | ||
| ... ] | ||
| >>> for x in sorted(some_values): | ||
| ... print(x) | ||
| FF-EE-00-01-02-03 | ||
| FF-EE-DD | ||
| FF-EE-DD-01-02-03 | ||
| FF-EE-DD-01-02-04 | ||
| Define New Types | ||
| ~~~~~~~~~~~~~~~~ | ||
| This library is designed to make it very easy | ||
| to use other hardware address types that this | ||
| library does not currently define for you. | ||
| For example, if you want to handle IP-over-InfiniBand | ||
| link-layer addresses, all you need to define is: | ||
| .. code:: python | ||
| class InfiniBand(macaddress.HWAddress): | ||
| size = 20 * 8 # size in bits; 20 octets | ||
| formats = ( | ||
| 'xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx', | ||
| 'xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx', | ||
| 'xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx', | ||
| 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', | ||
| # or whatever formats you want to support | ||
| ) | ||
| # All formats are tried when parsing from string, | ||
| # and the first format is used when stringifying. | ||
| Platform: UNKNOWN | ||
@@ -344,1 +14,362 @@ Classifier: Development Status :: 5 - Production/Stable | ||
| Classifier: Operating System :: OS Independent | ||
| License-File: LICENSE | ||
| macaddress | ||
| ========== | ||
| A module for handling hardware identifiers like MAC addresses. | ||
| This module makes it easy to: | ||
| 1. check if a string represents a valid MAC address, or a similar | ||
| hardware identifier like an EUI-64, OUI, etc, | ||
| 2. convert between string and binary forms of MAC addresses and | ||
| other hardware identifiers, | ||
| and so on. | ||
| Heavily inspired by the ``ipaddress`` module, but not yet quite | ||
| as featureful. | ||
| Versioning | ||
| ---------- | ||
| This library's version numbers follow the `SemVer 2.0.0 | ||
| specification <https://semver.org/spec/v2.0.0.html>`_. | ||
| Installation | ||
| ------------ | ||
| :: | ||
| pip install macaddress | ||
| Usage | ||
| ----- | ||
| Import: | ||
| .. code:: python | ||
| import macaddress | ||
| Classes are provided for the common hardware identifier | ||
| types: ``EUI48`` (also available as ``MAC``), ``EUI64``, | ||
| ``OUI``, and so on. If those aren't enough, you can | ||
| easily define others with just a few lines of code. | ||
| Parse or Validate String | ||
| ~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| When only one address type is valid: | ||
| ```````````````````````````````````` | ||
| All provided classes support the standard and common formats. | ||
| For example, the ``EUI48`` class supports the following | ||
| formats: | ||
| .. code:: python | ||
| >>> macaddress.EUI48('01-23-45-67-89-ab') | ||
| EUI48('01-23-45-67-89-AB') | ||
| >>> macaddress.EUI48('01:23:45:67:89:ab') | ||
| EUI48('01-23-45-67-89-AB') | ||
| >>> macaddress.EUI48('0123.4567.89ab') | ||
| EUI48('01-23-45-67-89-AB') | ||
| >>> macaddress.EUI48('0123456789ab') | ||
| EUI48('01-23-45-67-89-AB') | ||
| You can inspect what formats a hardware address class supports | ||
| by looking at its ``formats`` attribute: | ||
| .. code:: python | ||
| >>> macaddress.OUI.formats | ||
| ('xx-xx-xx', 'xx:xx:xx', 'xxxxxx') | ||
| Each ``x`` in the format string matches one hexadecimal | ||
| "digit", and all other characters are matched literally. | ||
| If the string does not match one of the formats, a | ||
| ``ValueError`` is raised: | ||
| .. code:: python | ||
| >>> try: | ||
| ... macaddress.MAC('foo bar') | ||
| ... except ValueError as error: | ||
| ... print(error) | ||
| ... | ||
| 'foo bar' cannot be parsed as EUI48 | ||
| If you need to parse in a format that isn't supported, | ||
| you can define a subclass and add the formats: | ||
| .. code:: python | ||
| >>> class MAC(macaddress.MAC): | ||
| ... formats = macaddress.MAC.formats + ( | ||
| ... 'xx-xx-xx-xx-xx-xx-', | ||
| ... 'xx:xx:xx:xx:xx:xx:', | ||
| ... 'xxxx.xxxx.xxxx.', | ||
| ... ) | ||
| ... | ||
| >>> MAC('01-02-03-04-05-06-') | ||
| MAC('01-02-03-04-05-06') | ||
| >>> class MAC(macaddress.MAC): | ||
| ... formats = macaddress.MAC.formats + ( | ||
| ... 'xxx-xxx-xxx-xxx', | ||
| ... 'xxx xxx xxx xxx', | ||
| ... 'xxx:xxx:xxx:xxx', | ||
| ... 'xxx.xxx.xxx.xxx', | ||
| ... ) | ||
| ... | ||
| >>> MAC('012 345 678 9AB') | ||
| MAC('01-23-45-67-89-AB') | ||
| When multiple address types are valid: | ||
| `````````````````````````````````````` | ||
| There is also a ``parse`` function for when you have a string | ||
| which might be one of several classes: | ||
| .. code:: python | ||
| >>> from macaddress import EUI48, EUI64, OUI | ||
| >>> macaddress.parse('01:02:03', OUI, EUI48) | ||
| OUI('01-02-03') | ||
| >>> macaddress.parse('01:02:03:04:05:06', OUI, EUI48, EUI64) | ||
| EUI48('01-02-03-04-05-06') | ||
| >>> macaddress.parse('010203040506', EUI64, EUI48) | ||
| EUI48('01-02-03-04-05-06') | ||
| >>> macaddress.parse('0102030405060708', EUI64, EUI48, OUI) | ||
| EUI64('01-02-03-04-05-06-07-08') | ||
| If the input string cannot be parsed as any of | ||
| the given classes, a ``ValueError`` is raised: | ||
| .. code:: python | ||
| >>> try: | ||
| ... macaddress.parse('01:23', EUI48, OUI) | ||
| ... except ValueError as error: | ||
| ... print(error) | ||
| ... | ||
| '01:23' cannot be parsed as EUI48 or OUI | ||
| >>> try: | ||
| ... macaddress.parse('01:23', EUI48, OUI, EUI64) | ||
| ... except ValueError as error: | ||
| ... print(error) | ||
| ... | ||
| '01:23' cannot be parsed as EUI48, OUI, or EUI64 | ||
| Note that the message of the ``ValueError`` tries to be helpful | ||
| for developers, but it is not localized, nor is its exact text | ||
| part of the official public interface covered by SemVer. | ||
| Parse from Bytes | ||
| ~~~~~~~~~~~~~~~~ | ||
| All ``macaddress`` classes can be constructed from raw bytes: | ||
| .. code:: python | ||
| >>> macaddress.MAC(b'abcdef') | ||
| EUI48('61-62-63-64-65-66') | ||
| >>> macaddress.OUI(b'abc') | ||
| OUI('61-62-63') | ||
| If the byte string is the wrong size, a ``ValueError`` is raised: | ||
| .. code:: python | ||
| >>> try: | ||
| ... macaddress.MAC(b'\x01\x02\x03') | ||
| ... except ValueError as error: | ||
| ... print(error) | ||
| ... | ||
| b'\x01\x02\x03' has wrong length for EUI48 | ||
| Parse from Integers | ||
| ~~~~~~~~~~~~~~~~~~~ | ||
| All ``macaddress`` classes can be constructed from raw integers: | ||
| .. code:: python | ||
| >>> macaddress.MAC(0x010203ffeedd) | ||
| EUI48('01-02-03-FF-EE-DD') | ||
| >>> macaddress.OUI(0x010203) | ||
| OUI('01-02-03') | ||
| Note that the least-significant bit of the integer value maps | ||
| to the last bit in the address type, so the same integer has | ||
| a different meaning depending on the class you use it with: | ||
| .. code:: python | ||
| >>> macaddress.MAC(1) | ||
| EUI48('00-00-00-00-00-01') | ||
| >>> macaddress.OUI(1) | ||
| OUI('00-00-01') | ||
| If the integer is too large for the hardware identifier class | ||
| that you're trying to construct, a ``ValueError`` is raised: | ||
| .. code:: python | ||
| >>> try: | ||
| ... macaddress.OUI(1_000_000_000) | ||
| ... except ValueError as error: | ||
| ... print(error) | ||
| ... | ||
| 1000000000 is too big for OUI | ||
| Get as String | ||
| ~~~~~~~~~~~~~ | ||
| .. code:: python | ||
| >>> mac = macaddress.MAC('01-02-03-0A-0B-0C') | ||
| >>> str(mac) | ||
| '01-02-03-0A-0B-0C' | ||
| For simple cases of changing the output format, you | ||
| can just compose string operations: | ||
| .. code:: python | ||
| >>> str(mac).replace('-', ':') | ||
| '01:02:03:0A:0B:0C' | ||
| >>> str(mac).replace('-', '') | ||
| '0102030A0B0C' | ||
| >>> str(mac).lower() | ||
| '01-02-03-0a-0b-0c' | ||
| For more complicated cases, you can define a subclass | ||
| with the desired output format as the first format: | ||
| .. code:: python | ||
| >>> class MAC(macaddress.MAC): | ||
| ... formats = ( | ||
| ... 'xxx xxx xxx xxx', | ||
| ... ) + macaddress.MAC.formats | ||
| ... | ||
| >>> MAC(mac) | ||
| MAC('010 203 0A0 B0C') | ||
| Get as Bytes | ||
| ~~~~~~~~~~~~ | ||
| .. code:: python | ||
| >>> mac = macaddress.MAC('61-62-63-04-05-06') | ||
| >>> bytes(mac) | ||
| b'abc\x04\x05\x06' | ||
| Get as Integer | ||
| ~~~~~~~~~~~~~~ | ||
| .. code:: python | ||
| >>> mac = macaddress.MAC('01-02-03-04-05-06') | ||
| >>> int(mac) | ||
| 1108152157446 | ||
| >>> int(mac) == 0x010203040506 | ||
| True | ||
| Get the OUI | ||
| ~~~~~~~~~~~ | ||
| Most classes supplied by this module have the ``oui`` | ||
| attribute, which returns their first three bytes as | ||
| an OUI object: | ||
| .. code:: python | ||
| >>> macaddress.MAC('01:02:03:04:05:06').oui | ||
| OUI('01-02-03') | ||
| Compare | ||
| ~~~~~~~ | ||
| Equality | ||
| ```````` | ||
| All ``macaddress`` classes support equality comparisons: | ||
| .. code:: python | ||
| >>> macaddress.OUI('01-02-03') == macaddress.OUI('01:02:03') | ||
| True | ||
| >>> macaddress.OUI('01-02-03') == macaddress.OUI('ff-ee-dd') | ||
| False | ||
| >>> macaddress.OUI('01-02-03') != macaddress.CDI32('01-02-03-04') | ||
| True | ||
| >>> macaddress.OUI('01-02-03') != macaddress.CDI32('01-02-03-04').oui | ||
| False | ||
| Ordering | ||
| ```````` | ||
| All ``macaddress`` classes support total | ||
| ordering. The comparisons are designed to | ||
| intuitively sort identifiers that start | ||
| with the same bits next to each other: | ||
| .. code:: python | ||
| >>> some_values = [ | ||
| ... MAC('ff-ee-dd-01-02-03'), | ||
| ... MAC('ff-ee-00-99-88-77'), | ||
| ... MAC('ff-ee-dd-01-02-04'), | ||
| ... OUI('ff-ee-dd'), | ||
| ... ] | ||
| >>> for x in sorted(some_values): | ||
| ... print(x) | ||
| FF-EE-00-01-02-03 | ||
| FF-EE-DD | ||
| FF-EE-DD-01-02-03 | ||
| FF-EE-DD-01-02-04 | ||
| Define New Types | ||
| ~~~~~~~~~~~~~~~~ | ||
| If this library does not provide a hardware address | ||
| type that you need, you can easily define your own. | ||
| For example, this is all it takes to define | ||
| IP-over-InfiniBand link-layer addresses: | ||
| .. code:: python | ||
| class InfiniBand(macaddress.HWAddress): | ||
| size = 20 * 8 # size in bits; 20 octets | ||
| formats = ( | ||
| 'xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx', | ||
| 'xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx', | ||
| 'xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx', | ||
| 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', | ||
| # or whatever formats you want to support | ||
| ) | ||
| # All formats are tried when parsing from string, | ||
| # and the first format is used when stringifying. | ||
+58
-83
@@ -14,5 +14,8 @@ # SPDX-License-Identifier: 0BSD | ||
| ) | ||
| __version__ = '1.2.0' | ||
| __version__ = '2.0.0' | ||
| from functools import total_ordering as _total_ordering | ||
| _HEX_DIGITS = "0123456789ABCDEFabcdef" | ||
@@ -47,2 +50,3 @@ | ||
| @_total_ordering | ||
| class HWAddress: | ||
@@ -66,4 +70,6 @@ """Base class for hardware addresses. | ||
| __slots__ = ('_address',) | ||
| __slots__ = ('_address', '__weakref__') | ||
| formats = () | ||
| def __init__(self, address): | ||
@@ -73,9 +79,9 @@ """Initialize the hardware address object with the address given. | ||
| Arguments: | ||
| address: An ``int``, ``bytes``, or ``str`` representation | ||
| of the address, or another instance of the same class | ||
| of address. If a string, the ``formats`` attribute of | ||
| the class is used to parse it. If a byte string, it | ||
| is read in big-endian. If an integer, its value bytes | ||
| in big-endian are used as the address bytes. If an | ||
| instance of the same address class, its value is used. | ||
| address: An ``int``, ``bytes``, or ``str`` representation of | ||
| the address, or another instance of an address which is | ||
| either the same class, a subclass, or a superclass. If a | ||
| string, the ``formats`` attribute of the class is used | ||
| to parse it. If a byte string, it is read in big-endian. | ||
| If an integer, its value bytes in big-endian are used as | ||
| the address bytes. | ||
@@ -90,3 +96,3 @@ Raises: | ||
| if isinstance(address, int): | ||
| overflow = 1 << self.size | ||
| overflow = 1 << type(self).size | ||
| if address >= overflow: | ||
@@ -99,11 +105,16 @@ raise _value_error(address, 'is too big for', type(self)) | ||
| length = len(address) | ||
| size_in_bytes = (self.size + 7) >> 3 | ||
| size_in_bytes = (type(self).size + 7) >> 3 | ||
| if length != size_in_bytes: | ||
| raise _value_error(address, 'has wrong length for', type(self)) | ||
| offset = (8 - self.size) & 7 | ||
| offset = (8 - type(self).size) & 7 | ||
| self._address = int.from_bytes(address, 'big') >> offset | ||
| elif isinstance(address, str): | ||
| elif isinstance(address, str) and len(type(self).formats): | ||
| self._address, _ = _parse(address, type(self)) | ||
| # Subclass being "cast" to superclass: | ||
| elif isinstance(address, type(self)): | ||
| self._address = address._address | ||
| # Superclass being "cast" to subclass: | ||
| elif (isinstance(address, HWAddress) | ||
| and isinstance(self, type(address))): | ||
| self._address = address._address | ||
| else: | ||
@@ -114,10 +125,17 @@ raise _type_error(address, type(self)) | ||
| """Represent the hardware address as an unambiguous string.""" | ||
| return _name(self) + '(' + repr(str(self)) + ')' | ||
| try: | ||
| address = str(self) | ||
| except TypeError: | ||
| address = bytes(self) | ||
| return _name(self) + '(' + repr(address) + ')' | ||
| def __str__(self): | ||
| """Get the canonical human-readable string of this hardware address.""" | ||
| formats = type(self).formats | ||
| if not len(formats): | ||
| raise TypeError(_name(self) + ' has no string format') | ||
| result = [] | ||
| offset = (4 - self.size) & 3 | ||
| offset = (4 - type(self).size) & 3 | ||
| unconsumed_address_value = self._address << offset | ||
| for character in reversed(self.formats[0]): | ||
| for character in reversed(formats[0]): | ||
| if character == 'x': | ||
@@ -133,4 +151,4 @@ nibble = unconsumed_address_value & 0xf | ||
| """Get the big-endian byte string of this hardware address.""" | ||
| offset = (8 - self.size) & 7 | ||
| size_in_bytes = (self.size + 7) >> 3 | ||
| offset = (8 - type(self).size) & 7 | ||
| size_in_bytes = (type(self).size + 7) >> 3 | ||
| return (self._address << offset).to_bytes(size_in_bytes, 'big') | ||
@@ -145,19 +163,9 @@ | ||
| They are equal if they are instances of the same class, | ||
| have the same size, and their addresses are equal. | ||
| Hardware addresses are equal if they are instances of the | ||
| same class, and their their raw bit strings are the same. | ||
| """ | ||
| if not isinstance(other, HWAddress): | ||
| return NotImplemented | ||
| if not isinstance(other, type(self)) or self.size != other.size: | ||
| return False | ||
| return self._address == other._address | ||
| return type(self) == type(other) and self._address == other._address | ||
| def __ne__(self, other): | ||
| """Check if this hardware address is not equal to another.""" | ||
| if not isinstance(other, HWAddress): | ||
| return NotImplemented | ||
| if not isinstance(other, type(self)) or self.size != other.size: | ||
| return True | ||
| return self._address != other._address | ||
| def __lt__(self, other): | ||
@@ -178,26 +186,14 @@ """Check if this hardware address is before another. | ||
| return NotImplemented | ||
| this, that = _aligned_address_integers(self, other) | ||
| return this < that or (this == that and self.size < other.size) | ||
| class1 = type(self) | ||
| class2 = type(other) | ||
| size1 = class1.size | ||
| size2 = class2.size | ||
| bits1 = int(self) | ||
| bits2 = int(other) | ||
| if size1 > size2: | ||
| bits2 <<= size1 - size2 | ||
| else: | ||
| bits1 <<= size2 - size1 | ||
| return (bits1, size1, id(class1)) < (bits2, size2, id(class2)) | ||
| def __le__(self, other): | ||
| """Check if this hardware address is before or equal to another.""" | ||
| if not isinstance(other, HWAddress): | ||
| return NotImplemented | ||
| this, that = _aligned_address_integers(self, other) | ||
| return this < that or (this == that and self.size <= other.size) | ||
| def __gt__(self, other): | ||
| """Check if this hardware address is after another.""" | ||
| if not isinstance(other, HWAddress): | ||
| return NotImplemented | ||
| this, that = _aligned_address_integers(self, other) | ||
| return this > that or (this == that and self.size > other.size) | ||
| def __ge__(self, other): | ||
| """Check if this hardware address is after or equal to another.""" | ||
| if not isinstance(other, HWAddress): | ||
| return NotImplemented | ||
| this, that = _aligned_address_integers(self, other) | ||
| return this > that or (this == that and self.size >= other.size) | ||
| def __hash__(self): | ||
@@ -208,11 +204,2 @@ """Get the hash of this hardware address.""" | ||
| def _aligned_address_integers(address1, address2): | ||
| size1 = address1.size | ||
| size2 = address2.size | ||
| if size1 > size2: | ||
| return (int(address1), int(address2) << (size1 - size2)) | ||
| else: | ||
| return (int(address1) << (size2 - size1), int(address2)) | ||
| class OUI(HWAddress): | ||
@@ -238,3 +225,3 @@ """Organizationally Unique Identifier.""" | ||
| """Get the OUI part of this hardware address.""" | ||
| return OUI(int(self) >> (self.size - OUI.size)) | ||
| return OUI(int(self) >> (type(self).size - OUI.size)) | ||
@@ -289,17 +276,5 @@ | ||
| class MAC(EUI48): | ||
| """MAC address. A subclass of EUI48. | ||
| MAC = EUI48 | ||
| There is nothing wrong with using EUI48 for MAC addresses, | ||
| this is just provided as a convenience for the many users | ||
| who will look for "MAC address" without knowing about EUI. | ||
| But it is a subclass instead of just an alias because it | ||
| might be nice in some situations to distinguish in code | ||
| between MAC addresses and other uses of EUI-48. | ||
| """ | ||
| __slots__ = () | ||
| class EUI60(_StartsWithOUI): | ||
@@ -339,3 +314,3 @@ """60-Bit Extended Unique Identifier (EUI-60).""" | ||
| address = hwaddress.parse(user_input, EUI64, EUI48, ...) | ||
| address = macaddress.parse(user_input, EUI64, EUI48, ...) | ||
@@ -345,6 +320,6 @@ instead of all of this: | ||
| try: | ||
| address = hwaddress.EUI64(user_input) | ||
| address = macaddress.EUI64(user_input) | ||
| except ValueError: | ||
| try: | ||
| address = hwaddress.EUI48(user_input) | ||
| address = macaddress.EUI48(user_input) | ||
| except ValueError: | ||
@@ -394,5 +369,5 @@ ... | ||
| for cls in classes: | ||
| for format in cls.formats: | ||
| if len(format) == length: | ||
| candidates.setdefault(format, cls) | ||
| for format_ in cls.formats: | ||
| if len(format_) == length: | ||
| candidates.setdefault(format_, cls) | ||
| candidates = sorted(candidates.items()) | ||
@@ -399,0 +374,0 @@ address = 0 |
+363
-332
@@ -1,4 +0,4 @@ | ||
| Metadata-Version: 1.1 | ||
| Metadata-Version: 2.1 | ||
| Name: macaddress | ||
| Version: 1.2.0 | ||
| Version: 2.0.0 | ||
| Summary: Like ``ipaddress``, but for hardware identifiers such as MAC addresses. | ||
@@ -9,332 +9,2 @@ Home-page: https://github.com/mentalisttraceur/python-macaddress | ||
| License: 0BSD | ||
| Description: macaddress | ||
| ========== | ||
| A module for handling hardware identifiers like MAC addresses. | ||
| This module makes it easy to: | ||
| 1. check if a string represents a valid MAC address, or a similar | ||
| hardware identifier like an EUI-64, OUI, etc, | ||
| 2. convert between string and binary forms of MAC addresses and | ||
| other hardware identifiers, | ||
| and so on. | ||
| Heavily inspired by the ``ipaddress`` module, but not yet quite | ||
| as featureful. | ||
| Versioning | ||
| ---------- | ||
| This library's version numbers follow the `SemVer 2.0.0 | ||
| specification <https://semver.org/spec/v2.0.0.html>`_. | ||
| Installation | ||
| ------------ | ||
| :: | ||
| pip install macaddress | ||
| Usage | ||
| ----- | ||
| Import: | ||
| .. code:: python | ||
| import macaddress | ||
| Classes are provided for common hardware identifier | ||
| types (``MAC``/``EUI48``, ``EUI64``, ``OUI``, and | ||
| so on), as well as several less common ones. Others | ||
| might be added later. You can define ones that you | ||
| need in your code with just a few lines of code. | ||
| Parse or Validate String | ||
| ~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| When only one address type is valid: | ||
| ```````````````````````````````````` | ||
| All provided classes support the standard and common formats. | ||
| For example, the ``EUI48`` and ``MAC`` classes support the | ||
| following formats: | ||
| .. code:: python | ||
| >>> macaddress.MAC('01-23-45-67-89-ab') | ||
| MAC('01-23-45-67-89-AB') | ||
| >>> macaddress.MAC('01:23:45:67:89:ab') | ||
| MAC('01-23-45-67-89-AB') | ||
| >>> macaddress.MAC('0123.4567.89ab') | ||
| MAC('01-23-45-67-89-AB') | ||
| >>> macaddress.MAC('0123456789ab') | ||
| MAC('01-23-45-67-89-AB') | ||
| You can inspect what formats a hardware address class supports | ||
| by looking at its ``formats`` attribute: | ||
| .. code:: python | ||
| >>> macaddress.OUI.formats | ||
| ('xx-xx-xx', 'xx:xx:xx', 'xxxxxx') | ||
| Each ``x`` in the format string matches one hexadecimal | ||
| "digit", and all other characters are matched literally. | ||
| If the string does not match one of the formats, a | ||
| ``ValueError`` is raised: | ||
| .. code:: python | ||
| >>> try: | ||
| ... macaddress.MAC('foo bar') | ||
| ... except ValueError as error: | ||
| ... print(error) | ||
| ... | ||
| 'foo bar' cannot be parsed as MAC | ||
| If you need to parse in a format that isn't supported, | ||
| you can define a subclass and add the format: | ||
| .. code:: python | ||
| >>> class MACAllowsTrailingDelimiters(macaddress.MAC): | ||
| ... formats = macaddress.MAC.formats + ( | ||
| ... 'xx-xx-xx-xx-xx-xx-', | ||
| ... 'xx:xx:xx:xx:xx:xx:', | ||
| ... 'xxxx.xxxx.xxxx.', | ||
| ... ) | ||
| ... | ||
| >>> MACAllowsTrailingDelimiters('01-02-03-04-05-06-') | ||
| MACAllowsTrailingDelimiters('01-02-03-04-05-06') | ||
| When multiple address types are valid: | ||
| `````````````````````````````````````` | ||
| There is also a ``parse`` function for when you have a string | ||
| which might be one of several classes: | ||
| .. code:: python | ||
| >>> from macaddress import EUI48, EUI64, MAC, OUI | ||
| >>> macaddress.parse('01:02:03', OUI, MAC) | ||
| OUI('01-02-03') | ||
| >>> macaddress.parse('01:02:03:04:05:06', OUI, MAC, EUI64) | ||
| MAC('01-02-03-04-05-06') | ||
| >>> macaddress.parse('010203040506', EUI64, EUI48) | ||
| EUI48('01-02-03-04-05-06') | ||
| >>> macaddress.parse('0102030405060708', EUI64, EUI48, OUI, MAC) | ||
| EUI64('01-02-03-04-05-06-07-08') | ||
| If the input string cannot be parsed as any of | ||
| the given classes, a ``ValueError`` is raised: | ||
| .. code:: python | ||
| >>> try: | ||
| ... macaddress.parse('01:23', MAC, OUI) | ||
| ... except ValueError as error: | ||
| ... print(error) | ||
| ... | ||
| '01:23' cannot be parsed as MAC or OUI | ||
| >>> try: | ||
| ... macaddress.parse('01:23', MAC, OUI, EUI64) | ||
| ... except ValueError as error: | ||
| ... print(error) | ||
| ... | ||
| '01:23' cannot be parsed as MAC, OUI, or EUI64 | ||
| Note that the message of the ``ValueError`` tries to be helpful | ||
| for developers, but it is not localized, nor is its exact text | ||
| part of the official public interface covered by SemVer. | ||
| Parse from Bytes | ||
| ~~~~~~~~~~~~~~~~ | ||
| All ``macaddress`` classes can be constructed from raw bytes: | ||
| .. code:: python | ||
| >>> macaddress.MAC(b'abcdef') | ||
| MAC('61-62-63-64-65-66') | ||
| >>> macaddress.OUI(b'abc') | ||
| OUI('61-62-63') | ||
| If the byte string is the wrong size, a ``ValueError`` is raised: | ||
| .. code:: python | ||
| >>> try: | ||
| ... macaddress.MAC(b'\x01\x02\x03') | ||
| ... except ValueError as error: | ||
| ... print(error) | ||
| ... | ||
| b'\x01\x02\x03' has wrong length for MAC | ||
| Parse from Integers | ||
| ~~~~~~~~~~~~~~~~~~~ | ||
| All ``macaddress`` classes can be constructed from raw integers: | ||
| .. code:: python | ||
| >>> macaddress.MAC(0x010203ffeedd) | ||
| MAC('01-02-03-FF-EE-DD') | ||
| >>> macaddress.OUI(0x010203) | ||
| OUI('01-02-03') | ||
| Note that the least-significant bit of the integer value maps | ||
| to the last bit in the address type, so the same integer has | ||
| a different meaning depending on the class you use it with: | ||
| .. code:: python | ||
| >>> macaddress.MAC(1) | ||
| MAC('00-00-00-00-00-01') | ||
| >>> macaddress.OUI(1) | ||
| OUI('00-00-01') | ||
| If the integer is too large for the hardware identifier class | ||
| that you're trying to construct, a ``ValueError`` is raised: | ||
| .. code:: python | ||
| >>> try: | ||
| ... macaddress.OUI(1_000_000_000) | ||
| ... except ValueError as error: | ||
| ... print(error) | ||
| ... | ||
| 1000000000 is too big for OUI | ||
| Get as String | ||
| ~~~~~~~~~~~~~ | ||
| .. code:: python | ||
| >>> mac = macaddress.MAC('01-02-03-0A-0B-0C') | ||
| >>> str(mac) | ||
| '01-02-03-0A-0B-0C' | ||
| >>> str(mac).replace('-', ':') | ||
| '01:02:03:0A:0B:0C' | ||
| >>> str(mac).replace('-', '') | ||
| '0102030A0B0C' | ||
| >>> str(mac).lower() | ||
| '01-02-03-0a-0b-0c' | ||
| Get as Bytes | ||
| ~~~~~~~~~~~~ | ||
| .. code:: python | ||
| >>> mac = macaddress.MAC('61-62-63-04-05-06') | ||
| >>> bytes(mac) | ||
| b'abc\x04\x05\x06' | ||
| Get as Integer | ||
| ~~~~~~~~~~~~~~ | ||
| .. code:: python | ||
| >>> mac = macaddress.MAC('01-02-03-04-05-06') | ||
| >>> int(mac) | ||
| 1108152157446 | ||
| >>> int(mac) == 0x010203040506 | ||
| True | ||
| Get the OUI | ||
| ~~~~~~~~~~~ | ||
| Most classes supplied by this module have the ``oui`` | ||
| attribute, which returns their first three bytes as | ||
| an OUI object: | ||
| .. code:: python | ||
| >>> macaddress.MAC('01:02:03:04:05:06').oui | ||
| OUI('01-02-03') | ||
| Compare | ||
| ~~~~~~~ | ||
| Equality | ||
| ```````` | ||
| All ``macaddress`` classes support equality comparisons: | ||
| .. code:: python | ||
| >>> macaddress.OUI('01-02-03') == macaddress.OUI('01:02:03') | ||
| True | ||
| >>> macaddress.OUI('01-02-03') == macaddress.OUI('ff-ee-dd') | ||
| False | ||
| >>> macaddress.OUI('01-02-03') != macaddress.CDI32('01-02-03-04') | ||
| True | ||
| >>> macaddress.OUI('01-02-03') != macaddress.CDI32('01-02-03-04').oui | ||
| False | ||
| Ordering | ||
| ```````` | ||
| All ``macaddress`` classes support total | ||
| ordering. The comparisons are designed to | ||
| intuitively sort identifiers that start | ||
| with the same bits next to each other: | ||
| .. code:: python | ||
| >>> some_values = [ | ||
| ... MAC('ff-ee-dd-01-02-03'), | ||
| ... MAC('ff-ee-00-99-88-77'), | ||
| ... MAC('ff-ee-dd-01-02-04'), | ||
| ... OUI('ff-ee-dd'), | ||
| ... ] | ||
| >>> for x in sorted(some_values): | ||
| ... print(x) | ||
| FF-EE-00-01-02-03 | ||
| FF-EE-DD | ||
| FF-EE-DD-01-02-03 | ||
| FF-EE-DD-01-02-04 | ||
| Define New Types | ||
| ~~~~~~~~~~~~~~~~ | ||
| This library is designed to make it very easy | ||
| to use other hardware address types that this | ||
| library does not currently define for you. | ||
| For example, if you want to handle IP-over-InfiniBand | ||
| link-layer addresses, all you need to define is: | ||
| .. code:: python | ||
| class InfiniBand(macaddress.HWAddress): | ||
| size = 20 * 8 # size in bits; 20 octets | ||
| formats = ( | ||
| 'xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx', | ||
| 'xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx', | ||
| 'xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx', | ||
| 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', | ||
| # or whatever formats you want to support | ||
| ) | ||
| # All formats are tried when parsing from string, | ||
| # and the first format is used when stringifying. | ||
| Platform: UNKNOWN | ||
@@ -344,1 +14,362 @@ Classifier: Development Status :: 5 - Production/Stable | ||
| Classifier: Operating System :: OS Independent | ||
| License-File: LICENSE | ||
| macaddress | ||
| ========== | ||
| A module for handling hardware identifiers like MAC addresses. | ||
| This module makes it easy to: | ||
| 1. check if a string represents a valid MAC address, or a similar | ||
| hardware identifier like an EUI-64, OUI, etc, | ||
| 2. convert between string and binary forms of MAC addresses and | ||
| other hardware identifiers, | ||
| and so on. | ||
| Heavily inspired by the ``ipaddress`` module, but not yet quite | ||
| as featureful. | ||
| Versioning | ||
| ---------- | ||
| This library's version numbers follow the `SemVer 2.0.0 | ||
| specification <https://semver.org/spec/v2.0.0.html>`_. | ||
| Installation | ||
| ------------ | ||
| :: | ||
| pip install macaddress | ||
| Usage | ||
| ----- | ||
| Import: | ||
| .. code:: python | ||
| import macaddress | ||
| Classes are provided for the common hardware identifier | ||
| types: ``EUI48`` (also available as ``MAC``), ``EUI64``, | ||
| ``OUI``, and so on. If those aren't enough, you can | ||
| easily define others with just a few lines of code. | ||
| Parse or Validate String | ||
| ~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| When only one address type is valid: | ||
| ```````````````````````````````````` | ||
| All provided classes support the standard and common formats. | ||
| For example, the ``EUI48`` class supports the following | ||
| formats: | ||
| .. code:: python | ||
| >>> macaddress.EUI48('01-23-45-67-89-ab') | ||
| EUI48('01-23-45-67-89-AB') | ||
| >>> macaddress.EUI48('01:23:45:67:89:ab') | ||
| EUI48('01-23-45-67-89-AB') | ||
| >>> macaddress.EUI48('0123.4567.89ab') | ||
| EUI48('01-23-45-67-89-AB') | ||
| >>> macaddress.EUI48('0123456789ab') | ||
| EUI48('01-23-45-67-89-AB') | ||
| You can inspect what formats a hardware address class supports | ||
| by looking at its ``formats`` attribute: | ||
| .. code:: python | ||
| >>> macaddress.OUI.formats | ||
| ('xx-xx-xx', 'xx:xx:xx', 'xxxxxx') | ||
| Each ``x`` in the format string matches one hexadecimal | ||
| "digit", and all other characters are matched literally. | ||
| If the string does not match one of the formats, a | ||
| ``ValueError`` is raised: | ||
| .. code:: python | ||
| >>> try: | ||
| ... macaddress.MAC('foo bar') | ||
| ... except ValueError as error: | ||
| ... print(error) | ||
| ... | ||
| 'foo bar' cannot be parsed as EUI48 | ||
| If you need to parse in a format that isn't supported, | ||
| you can define a subclass and add the formats: | ||
| .. code:: python | ||
| >>> class MAC(macaddress.MAC): | ||
| ... formats = macaddress.MAC.formats + ( | ||
| ... 'xx-xx-xx-xx-xx-xx-', | ||
| ... 'xx:xx:xx:xx:xx:xx:', | ||
| ... 'xxxx.xxxx.xxxx.', | ||
| ... ) | ||
| ... | ||
| >>> MAC('01-02-03-04-05-06-') | ||
| MAC('01-02-03-04-05-06') | ||
| >>> class MAC(macaddress.MAC): | ||
| ... formats = macaddress.MAC.formats + ( | ||
| ... 'xxx-xxx-xxx-xxx', | ||
| ... 'xxx xxx xxx xxx', | ||
| ... 'xxx:xxx:xxx:xxx', | ||
| ... 'xxx.xxx.xxx.xxx', | ||
| ... ) | ||
| ... | ||
| >>> MAC('012 345 678 9AB') | ||
| MAC('01-23-45-67-89-AB') | ||
| When multiple address types are valid: | ||
| `````````````````````````````````````` | ||
| There is also a ``parse`` function for when you have a string | ||
| which might be one of several classes: | ||
| .. code:: python | ||
| >>> from macaddress import EUI48, EUI64, OUI | ||
| >>> macaddress.parse('01:02:03', OUI, EUI48) | ||
| OUI('01-02-03') | ||
| >>> macaddress.parse('01:02:03:04:05:06', OUI, EUI48, EUI64) | ||
| EUI48('01-02-03-04-05-06') | ||
| >>> macaddress.parse('010203040506', EUI64, EUI48) | ||
| EUI48('01-02-03-04-05-06') | ||
| >>> macaddress.parse('0102030405060708', EUI64, EUI48, OUI) | ||
| EUI64('01-02-03-04-05-06-07-08') | ||
| If the input string cannot be parsed as any of | ||
| the given classes, a ``ValueError`` is raised: | ||
| .. code:: python | ||
| >>> try: | ||
| ... macaddress.parse('01:23', EUI48, OUI) | ||
| ... except ValueError as error: | ||
| ... print(error) | ||
| ... | ||
| '01:23' cannot be parsed as EUI48 or OUI | ||
| >>> try: | ||
| ... macaddress.parse('01:23', EUI48, OUI, EUI64) | ||
| ... except ValueError as error: | ||
| ... print(error) | ||
| ... | ||
| '01:23' cannot be parsed as EUI48, OUI, or EUI64 | ||
| Note that the message of the ``ValueError`` tries to be helpful | ||
| for developers, but it is not localized, nor is its exact text | ||
| part of the official public interface covered by SemVer. | ||
| Parse from Bytes | ||
| ~~~~~~~~~~~~~~~~ | ||
| All ``macaddress`` classes can be constructed from raw bytes: | ||
| .. code:: python | ||
| >>> macaddress.MAC(b'abcdef') | ||
| EUI48('61-62-63-64-65-66') | ||
| >>> macaddress.OUI(b'abc') | ||
| OUI('61-62-63') | ||
| If the byte string is the wrong size, a ``ValueError`` is raised: | ||
| .. code:: python | ||
| >>> try: | ||
| ... macaddress.MAC(b'\x01\x02\x03') | ||
| ... except ValueError as error: | ||
| ... print(error) | ||
| ... | ||
| b'\x01\x02\x03' has wrong length for EUI48 | ||
| Parse from Integers | ||
| ~~~~~~~~~~~~~~~~~~~ | ||
| All ``macaddress`` classes can be constructed from raw integers: | ||
| .. code:: python | ||
| >>> macaddress.MAC(0x010203ffeedd) | ||
| EUI48('01-02-03-FF-EE-DD') | ||
| >>> macaddress.OUI(0x010203) | ||
| OUI('01-02-03') | ||
| Note that the least-significant bit of the integer value maps | ||
| to the last bit in the address type, so the same integer has | ||
| a different meaning depending on the class you use it with: | ||
| .. code:: python | ||
| >>> macaddress.MAC(1) | ||
| EUI48('00-00-00-00-00-01') | ||
| >>> macaddress.OUI(1) | ||
| OUI('00-00-01') | ||
| If the integer is too large for the hardware identifier class | ||
| that you're trying to construct, a ``ValueError`` is raised: | ||
| .. code:: python | ||
| >>> try: | ||
| ... macaddress.OUI(1_000_000_000) | ||
| ... except ValueError as error: | ||
| ... print(error) | ||
| ... | ||
| 1000000000 is too big for OUI | ||
| Get as String | ||
| ~~~~~~~~~~~~~ | ||
| .. code:: python | ||
| >>> mac = macaddress.MAC('01-02-03-0A-0B-0C') | ||
| >>> str(mac) | ||
| '01-02-03-0A-0B-0C' | ||
| For simple cases of changing the output format, you | ||
| can just compose string operations: | ||
| .. code:: python | ||
| >>> str(mac).replace('-', ':') | ||
| '01:02:03:0A:0B:0C' | ||
| >>> str(mac).replace('-', '') | ||
| '0102030A0B0C' | ||
| >>> str(mac).lower() | ||
| '01-02-03-0a-0b-0c' | ||
| For more complicated cases, you can define a subclass | ||
| with the desired output format as the first format: | ||
| .. code:: python | ||
| >>> class MAC(macaddress.MAC): | ||
| ... formats = ( | ||
| ... 'xxx xxx xxx xxx', | ||
| ... ) + macaddress.MAC.formats | ||
| ... | ||
| >>> MAC(mac) | ||
| MAC('010 203 0A0 B0C') | ||
| Get as Bytes | ||
| ~~~~~~~~~~~~ | ||
| .. code:: python | ||
| >>> mac = macaddress.MAC('61-62-63-04-05-06') | ||
| >>> bytes(mac) | ||
| b'abc\x04\x05\x06' | ||
| Get as Integer | ||
| ~~~~~~~~~~~~~~ | ||
| .. code:: python | ||
| >>> mac = macaddress.MAC('01-02-03-04-05-06') | ||
| >>> int(mac) | ||
| 1108152157446 | ||
| >>> int(mac) == 0x010203040506 | ||
| True | ||
| Get the OUI | ||
| ~~~~~~~~~~~ | ||
| Most classes supplied by this module have the ``oui`` | ||
| attribute, which returns their first three bytes as | ||
| an OUI object: | ||
| .. code:: python | ||
| >>> macaddress.MAC('01:02:03:04:05:06').oui | ||
| OUI('01-02-03') | ||
| Compare | ||
| ~~~~~~~ | ||
| Equality | ||
| ```````` | ||
| All ``macaddress`` classes support equality comparisons: | ||
| .. code:: python | ||
| >>> macaddress.OUI('01-02-03') == macaddress.OUI('01:02:03') | ||
| True | ||
| >>> macaddress.OUI('01-02-03') == macaddress.OUI('ff-ee-dd') | ||
| False | ||
| >>> macaddress.OUI('01-02-03') != macaddress.CDI32('01-02-03-04') | ||
| True | ||
| >>> macaddress.OUI('01-02-03') != macaddress.CDI32('01-02-03-04').oui | ||
| False | ||
| Ordering | ||
| ```````` | ||
| All ``macaddress`` classes support total | ||
| ordering. The comparisons are designed to | ||
| intuitively sort identifiers that start | ||
| with the same bits next to each other: | ||
| .. code:: python | ||
| >>> some_values = [ | ||
| ... MAC('ff-ee-dd-01-02-03'), | ||
| ... MAC('ff-ee-00-99-88-77'), | ||
| ... MAC('ff-ee-dd-01-02-04'), | ||
| ... OUI('ff-ee-dd'), | ||
| ... ] | ||
| >>> for x in sorted(some_values): | ||
| ... print(x) | ||
| FF-EE-00-01-02-03 | ||
| FF-EE-DD | ||
| FF-EE-DD-01-02-03 | ||
| FF-EE-DD-01-02-04 | ||
| Define New Types | ||
| ~~~~~~~~~~~~~~~~ | ||
| If this library does not provide a hardware address | ||
| type that you need, you can easily define your own. | ||
| For example, this is all it takes to define | ||
| IP-over-InfiniBand link-layer addresses: | ||
| .. code:: python | ||
| class InfiniBand(macaddress.HWAddress): | ||
| size = 20 * 8 # size in bits; 20 octets | ||
| formats = ( | ||
| 'xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx', | ||
| 'xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx', | ||
| 'xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx', | ||
| 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', | ||
| # or whatever formats you want to support | ||
| ) | ||
| # All formats are tried when parsing from string, | ||
| # and the first format is used when stringifying. | ||
+72
-44
@@ -44,7 +44,6 @@ macaddress | ||
| Classes are provided for common hardware identifier | ||
| types (``MAC``/``EUI48``, ``EUI64``, ``OUI``, and | ||
| so on), as well as several less common ones. Others | ||
| might be added later. You can define ones that you | ||
| need in your code with just a few lines of code. | ||
| Classes are provided for the common hardware identifier | ||
| types: ``EUI48`` (also available as ``MAC``), ``EUI64``, | ||
| ``OUI``, and so on. If those aren't enough, you can | ||
| easily define others with just a few lines of code. | ||
@@ -59,15 +58,15 @@ | ||
| All provided classes support the standard and common formats. | ||
| For example, the ``EUI48`` and ``MAC`` classes support the | ||
| following formats: | ||
| For example, the ``EUI48`` class supports the following | ||
| formats: | ||
| .. code:: python | ||
| >>> macaddress.MAC('01-23-45-67-89-ab') | ||
| MAC('01-23-45-67-89-AB') | ||
| >>> macaddress.MAC('01:23:45:67:89:ab') | ||
| MAC('01-23-45-67-89-AB') | ||
| >>> macaddress.MAC('0123.4567.89ab') | ||
| MAC('01-23-45-67-89-AB') | ||
| >>> macaddress.MAC('0123456789ab') | ||
| MAC('01-23-45-67-89-AB') | ||
| >>> macaddress.EUI48('01-23-45-67-89-ab') | ||
| EUI48('01-23-45-67-89-AB') | ||
| >>> macaddress.EUI48('01:23:45:67:89:ab') | ||
| EUI48('01-23-45-67-89-AB') | ||
| >>> macaddress.EUI48('0123.4567.89ab') | ||
| EUI48('01-23-45-67-89-AB') | ||
| >>> macaddress.EUI48('0123456789ab') | ||
| EUI48('01-23-45-67-89-AB') | ||
@@ -94,11 +93,11 @@ You can inspect what formats a hardware address class supports | ||
| ... print(error) | ||
| ... | ||
| 'foo bar' cannot be parsed as MAC | ||
| ... | ||
| 'foo bar' cannot be parsed as EUI48 | ||
| If you need to parse in a format that isn't supported, | ||
| you can define a subclass and add the format: | ||
| you can define a subclass and add the formats: | ||
| .. code:: python | ||
| >>> class MACAllowsTrailingDelimiters(macaddress.MAC): | ||
| >>> class MAC(macaddress.MAC): | ||
| ... formats = macaddress.MAC.formats + ( | ||
@@ -109,6 +108,17 @@ ... 'xx-xx-xx-xx-xx-xx-', | ||
| ... ) | ||
| ... | ||
| >>> MACAllowsTrailingDelimiters('01-02-03-04-05-06-') | ||
| MACAllowsTrailingDelimiters('01-02-03-04-05-06') | ||
| ... | ||
| >>> MAC('01-02-03-04-05-06-') | ||
| MAC('01-02-03-04-05-06') | ||
| >>> class MAC(macaddress.MAC): | ||
| ... formats = macaddress.MAC.formats + ( | ||
| ... 'xxx-xxx-xxx-xxx', | ||
| ... 'xxx xxx xxx xxx', | ||
| ... 'xxx:xxx:xxx:xxx', | ||
| ... 'xxx.xxx.xxx.xxx', | ||
| ... ) | ||
| ... | ||
| >>> MAC('012 345 678 9AB') | ||
| MAC('01-23-45-67-89-AB') | ||
| When multiple address types are valid: | ||
@@ -122,11 +132,11 @@ `````````````````````````````````````` | ||
| >>> from macaddress import EUI48, EUI64, MAC, OUI | ||
| >>> from macaddress import EUI48, EUI64, OUI | ||
| >>> macaddress.parse('01:02:03', OUI, MAC) | ||
| >>> macaddress.parse('01:02:03', OUI, EUI48) | ||
| OUI('01-02-03') | ||
| >>> macaddress.parse('01:02:03:04:05:06', OUI, MAC, EUI64) | ||
| MAC('01-02-03-04-05-06') | ||
| >>> macaddress.parse('01:02:03:04:05:06', OUI, EUI48, EUI64) | ||
| EUI48('01-02-03-04-05-06') | ||
| >>> macaddress.parse('010203040506', EUI64, EUI48) | ||
| EUI48('01-02-03-04-05-06') | ||
| >>> macaddress.parse('0102030405060708', EUI64, EUI48, OUI, MAC) | ||
| >>> macaddress.parse('0102030405060708', EUI64, EUI48, OUI) | ||
| EUI64('01-02-03-04-05-06-07-08') | ||
@@ -140,13 +150,13 @@ | ||
| >>> try: | ||
| ... macaddress.parse('01:23', MAC, OUI) | ||
| ... macaddress.parse('01:23', EUI48, OUI) | ||
| ... except ValueError as error: | ||
| ... print(error) | ||
| ... | ||
| '01:23' cannot be parsed as MAC or OUI | ||
| ... | ||
| '01:23' cannot be parsed as EUI48 or OUI | ||
| >>> try: | ||
| ... macaddress.parse('01:23', MAC, OUI, EUI64) | ||
| ... macaddress.parse('01:23', EUI48, OUI, EUI64) | ||
| ... except ValueError as error: | ||
| ... print(error) | ||
| ... | ||
| '01:23' cannot be parsed as MAC, OUI, or EUI64 | ||
| ... | ||
| '01:23' cannot be parsed as EUI48, OUI, or EUI64 | ||
@@ -166,3 +176,3 @@ Note that the message of the ``ValueError`` tries to be helpful | ||
| >>> macaddress.MAC(b'abcdef') | ||
| MAC('61-62-63-64-65-66') | ||
| EUI48('61-62-63-64-65-66') | ||
| >>> macaddress.OUI(b'abc') | ||
@@ -179,4 +189,4 @@ OUI('61-62-63') | ||
| ... print(error) | ||
| ... | ||
| b'\x01\x02\x03' has wrong length for MAC | ||
| ... | ||
| b'\x01\x02\x03' has wrong length for EUI48 | ||
@@ -192,3 +202,3 @@ | ||
| >>> macaddress.MAC(0x010203ffeedd) | ||
| MAC('01-02-03-FF-EE-DD') | ||
| EUI48('01-02-03-FF-EE-DD') | ||
| >>> macaddress.OUI(0x010203) | ||
@@ -204,3 +214,3 @@ OUI('01-02-03') | ||
| >>> macaddress.MAC(1) | ||
| MAC('00-00-00-00-00-01') | ||
| EUI48('00-00-00-00-00-01') | ||
| >>> macaddress.OUI(1) | ||
@@ -218,3 +228,3 @@ OUI('00-00-01') | ||
| ... print(error) | ||
| ... | ||
| ... | ||
| 1000000000 is too big for OUI | ||
@@ -231,2 +241,8 @@ | ||
| '01-02-03-0A-0B-0C' | ||
| For simple cases of changing the output format, you | ||
| can just compose string operations: | ||
| .. code:: python | ||
| >>> str(mac).replace('-', ':') | ||
@@ -239,3 +255,16 @@ '01:02:03:0A:0B:0C' | ||
| For more complicated cases, you can define a subclass | ||
| with the desired output format as the first format: | ||
| .. code:: python | ||
| >>> class MAC(macaddress.MAC): | ||
| ... formats = ( | ||
| ... 'xxx xxx xxx xxx', | ||
| ... ) + macaddress.MAC.formats | ||
| ... | ||
| >>> MAC(mac) | ||
| MAC('010 203 0A0 B0C') | ||
| Get as Bytes | ||
@@ -322,8 +351,7 @@ ~~~~~~~~~~~~ | ||
| This library is designed to make it very easy | ||
| to use other hardware address types that this | ||
| library does not currently define for you. | ||
| If this library does not provide a hardware address | ||
| type that you need, you can easily define your own. | ||
| For example, if you want to handle IP-over-InfiniBand | ||
| link-layer addresses, all you need to define is: | ||
| For example, this is all it takes to define | ||
| IP-over-InfiniBand link-layer addresses: | ||
@@ -330,0 +358,0 @@ .. code:: python |
Alert delta unavailable
Currently unable to show alert delta for PyPI packages.
39629
-10.56%327
-5.49%