Latest Threat Research:SANDWORM_MODE: Shai-Hulud-Style npm Worm Hijacks CI Workflows and Poisons AI Toolchains.Details
Socket
Book a DemoInstallSign in
Socket

macaddress

Package Overview
Dependencies
Maintainers
1
Versions
10
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

macaddress - npm Package Compare versions

Comparing version
1.2.0
to
2.0.0
+363
-332
macaddress.egg-info/PKG-INFO

@@ -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.

@@ -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.

@@ -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