Serhiy Storchaka added the comment:

Here are updated patches for 3.5 (using subprocess) and 3.4 (using os.popen) 
which addresses Victor's comments.

----------
Added file: http://bugs.python.org/file36998/uuid_netstat_getnode-3.5_2.patch
Added file: http://bugs.python.org/file36999/uuid_netstat_getnode-3.4.patch

_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue17293>
_______________________________________
diff -r f2ce9603346c Lib/test/test_uuid.py
--- a/Lib/test/test_uuid.py     Wed Oct 22 12:33:23 2014 +0200
+++ b/Lib/test/test_uuid.py     Thu Oct 23 12:57:55 2014 +0300
@@ -320,6 +320,24 @@ class TestUUID(unittest.TestCase):
         if node is not None:
             self.check_node(node, 'ifconfig')
 
+    @unittest.skipUnless(os.name == 'posix', 'requires Posix')
+    def test_arp_getnode(self):
+        node = uuid._arp_getnode()
+        if node is not None:
+            self.check_node(node, 'arp')
+
+    @unittest.skipUnless(os.name == 'posix', 'requires Posix')
+    def test_lanscan_getnode(self):
+        node = uuid._lanscan_getnode()
+        if node is not None:
+            self.check_node(node, 'lanscan')
+
+    @unittest.skipUnless(os.name == 'posix', 'requires Posix')
+    def test_netstat_getnode(self):
+        node = uuid._netstat_getnode()
+        if node is not None:
+            self.check_node(node, 'netstat')
+
     @unittest.skipUnless(os.name == 'nt', 'requires Windows')
     def test_ipconfig_getnode(self):
         node = uuid._ipconfig_getnode()
@@ -377,7 +395,7 @@ eth0      Link encap:Ethernet  HWaddr 12
                                             return_value=popen):
                 mac = uuid._find_mac(
                     command='ifconfig',
-                    arg='',
+                    args='',
                     hw_identifiers=[b'hwaddr'],
                     get_index=lambda x: x + 1,
                 )
diff -r f2ce9603346c Lib/uuid.py
--- a/Lib/uuid.py       Wed Oct 22 12:33:23 2014 +0200
+++ b/Lib/uuid.py       Thu Oct 23 12:57:55 2014 +0300
@@ -304,7 +304,7 @@ class UUID(object):
         if self.variant == RFC_4122:
             return int((self.int >> 76) & 0xf)
 
-def _find_mac(command, arg, hw_identifiers, get_index):
+def _popen(command, *args):
     import os, shutil, subprocess
     executable = shutil.which(command)
     if executable is None:
@@ -312,28 +312,32 @@ def _find_mac(command, arg, hw_identifie
         executable = shutil.which(command, path=path)
         if executable is None:
             return None
+    # LC_ALL=C to ensure English output, stderr=DEVNULL to prevent output
+    # on stderr (Note: we don't have an example where the words we search
+    # for are actually localized, but in theory some system could do so.)
+    env = dict(os.environ)
+    env['LC_ALL'] = 'C'
+    proc = subprocess.Popen((executable,) + args,
+                            stdout=subprocess.PIPE,
+                            stderr=subprocess.DEVNULL,
+                            env=env)
+    return proc
 
+def _find_mac(command, args, hw_identifiers, get_index):
     try:
-        # LC_ALL=C to ensure English output, stderr=DEVNULL to prevent output
-        # on stderr (Note: we don't have an example where the words we search
-        # for are actually localized, but in theory some system could do so.)
-        env = dict(os.environ)
-        env['LC_ALL'] = 'C'
-        cmd = [executable]
-        if arg:
-            cmd.append(arg)
-        proc = subprocess.Popen(cmd,
-                                stdout=subprocess.PIPE,
-                                stderr=subprocess.DEVNULL,
-                                env=env)
+        proc = _popen(command, *args.split())
+        if not proc:
+            return
         with proc:
             for line in proc.stdout:
-                words = line.lower().split()
+                words = line.lower().rstrip().split()
                 for i in range(len(words)):
                     if words[i] in hw_identifiers:
                         try:
-                            return int(
-                                words[get_index(i)].replace(b':', b''), 16)
+                            word = words[get_index(i)]
+                            mac = int(word.replace(b':', b''), 16)
+                            if mac:
+                                return mac
                         except (ValueError, IndexError):
                             # Virtual interfaces, such as those provided by
                             # VPNs, do not have a colon-delimited MAC address
@@ -346,27 +350,50 @@ def _find_mac(command, arg, hw_identifie
 
 def _ifconfig_getnode():
     """Get the hardware address on Unix by running ifconfig."""
-
     # This works on Linux ('' or '-a'), Tru64 ('-av'), but not all Unixes.
     for args in ('', '-a', '-av'):
         mac = _find_mac('ifconfig', args, [b'hwaddr', b'ether'], lambda i: i+1)
         if mac:
             return mac
 
-    import socket
+def _arp_getnode():
+    """Get the hardware address on Unix by running arp."""
+    import os, socket
     ip_addr = socket.gethostbyname(socket.gethostname())
 
     # Try getting the MAC addr from arp based on our IP address (Solaris).
-    mac = _find_mac('arp', '-an', [os.fsencode(ip_addr)], lambda i: -1)
-    if mac:
-        return mac
+    return _find_mac('arp', '-an', [os.fsencode(ip_addr)], lambda i: -1)
 
+def _lanscan_getnode():
+    """Get the hardware address on Unix by running lanscan."""
     # This might work on HP-UX.
-    mac = _find_mac('lanscan', '-ai', [b'lan0'], lambda i: 0)
-    if mac:
-        return mac
+    return _find_mac('lanscan', '-ai', [b'lan0'], lambda i: 0)
 
-    return None
+def _netstat_getnode():
+    """Get the hardware address on Unix by running netstat."""
+    # This might work on AIX, Tru64 UNIX and presumably on IRIX.
+    try:
+        proc = _popen('netstat', '-ia')
+        if not proc:
+            return
+        with proc:
+            words = proc.stdout.readline().rstrip().split()
+            try:
+                i = words.index(b'Address')
+            except ValueError:
+                return
+            for line in proc.stdout:
+                try:
+                    words = line.rstrip().split()
+                    word = words[i]
+                    if len(word) == 17 and word.count(b':') == 5:
+                        mac = int(word.replace(b':', b''), 16)
+                        if mac:
+                            return mac
+                except (ValueError, IndexError):
+                    pass
+    except OSError:
+        pass
 
 def _ipconfig_getnode():
     """Get the hardware address on Windows by running ipconfig.exe."""
@@ -508,7 +535,8 @@ def getnode():
     if sys.platform == 'win32':
         getters = [_windll_getnode, _netbios_getnode, _ipconfig_getnode]
     else:
-        getters = [_unixdll_getnode, _ifconfig_getnode]
+        getters = [_unixdll_getnode, _ifconfig_getnode, _arp_getnode,
+                   _lanscan_getnode, _netstat_getnode]
 
     for getter in getters + [_random_getnode]:
         try:
diff -r a2ecc284eaa7 Lib/test/test_uuid.py
--- a/Lib/test/test_uuid.py     Wed Oct 22 09:55:44 2014 +0200
+++ b/Lib/test/test_uuid.py     Thu Oct 23 13:13:27 2014 +0300
@@ -319,6 +319,24 @@ class TestUUID(unittest.TestCase):
         if node is not None:
             self.check_node(node, 'ifconfig')
 
+    @unittest.skipUnless(os.name == 'posix', 'requires Posix')
+    def test_arp_getnode(self):
+        node = uuid._arp_getnode()
+        if node is not None:
+            self.check_node(node, 'arp')
+
+    @unittest.skipUnless(os.name == 'posix', 'requires Posix')
+    def test_lanscan_getnode(self):
+        node = uuid._lanscan_getnode()
+        if node is not None:
+            self.check_node(node, 'lanscan')
+
+    @unittest.skipUnless(os.name == 'posix', 'requires Posix')
+    def test_netstat_getnode(self):
+        node = uuid._netstat_getnode()
+        if node is not None:
+            self.check_node(node, 'netstat')
+
     @unittest.skipUnless(os.name == 'nt', 'requires Windows')
     def test_ipconfig_getnode(self):
         node = uuid._ipconfig_getnode()
diff -r a2ecc284eaa7 Lib/uuid.py
--- a/Lib/uuid.py       Wed Oct 22 09:55:44 2014 +0200
+++ b/Lib/uuid.py       Thu Oct 23 13:13:27 2014 +0300
@@ -311,7 +311,7 @@ class UUID(object):
         if self.variant == RFC_4122:
             return int((self.int >> 76) & 0xf)
 
-def _find_mac(command, args, hw_identifiers, get_index):
+def _popen(command, args):
     import os, shutil
     executable = shutil.which(command)
     if executable is None:
@@ -319,20 +319,27 @@ def _find_mac(command, args, hw_identifi
         executable = shutil.which(command, path=path)
         if executable is None:
             return None
+    # LC_ALL to ensure English output, 2>/dev/null to prevent output on
+    # stderr (Note: we don't have an example where the words we search for
+    # are actually localized, but in theory some system could do so.)
+    cmd = 'LC_ALL=C %s %s 2>/dev/null' % (executable, args)
+    return os.popen(cmd)
 
+def _find_mac(command, args, hw_identifiers, get_index):
     try:
-        # LC_ALL to ensure English output, 2>/dev/null to prevent output on
-        # stderr (Note: we don't have an example where the words we search for
-        # are actually localized, but in theory some system could do so.)
-        cmd = 'LC_ALL=C %s %s 2>/dev/null' % (executable, args)
-        with os.popen(cmd) as pipe:
+        pipe = _popen(command, args)
+        if not pipe:
+            return
+        with pipe:
             for line in pipe:
-                words = line.lower().split()
+                words = line.lower().rstrip().split()
                 for i in range(len(words)):
                     if words[i] in hw_identifiers:
                         try:
-                            return int(
-                                words[get_index(i)].replace(':', ''), 16)
+                            word = words[get_index(i)]
+                            mac = int(word.replace(':', ''), 16)
+                            if mac:
+                                return mac
                         except (ValueError, IndexError):
                             # Virtual interfaces, such as those provided by
                             # VPNs, do not have a colon-delimited MAC address
@@ -345,27 +352,50 @@ def _find_mac(command, args, hw_identifi
 
 def _ifconfig_getnode():
     """Get the hardware address on Unix by running ifconfig."""
-
     # This works on Linux ('' or '-a'), Tru64 ('-av'), but not all Unixes.
     for args in ('', '-a', '-av'):
         mac = _find_mac('ifconfig', args, ['hwaddr', 'ether'], lambda i: i+1)
         if mac:
             return mac
 
-    import socket
+def _arp_getnode():
+    """Get the hardware address on Unix by running arp."""
+    import os, socket
     ip_addr = socket.gethostbyname(socket.gethostname())
 
     # Try getting the MAC addr from arp based on our IP address (Solaris).
-    mac = _find_mac('arp', '-an', [ip_addr], lambda i: -1)
-    if mac:
-        return mac
+    return _find_mac('arp', '-an', [ip_addr], lambda i: -1)
 
+def _lanscan_getnode():
+    """Get the hardware address on Unix by running lanscan."""
     # This might work on HP-UX.
-    mac = _find_mac('lanscan', '-ai', ['lan0'], lambda i: 0)
-    if mac:
-        return mac
+    return _find_mac('lanscan', '-ai', ['lan0'], lambda i: 0)
 
-    return None
+def _netstat_getnode():
+    """Get the hardware address on Unix by running netstat."""
+    # This might work on AIX, Tru64 UNIX and presumably on IRIX.
+    try:
+        pipe = _popen('netstat', '-ia')
+        if not pipe:
+            return
+        with pipe:
+            words = pipe.readline().rstrip().split()
+            try:
+                i = words.index('Address')
+            except ValueError:
+                return
+            for line in pipe:
+                try:
+                    words = line.rstrip().split()
+                    word = words[i]
+                    if len(word) == 17 and word.count(':') == 5:
+                        mac = int(word.replace(':', ''), 16)
+                        if mac:
+                            return mac
+                except (ValueError, IndexError):
+                    pass
+    except OSError:
+        pass
 
 def _ipconfig_getnode():
     """Get the hardware address on Windows by running ipconfig.exe."""
@@ -506,7 +536,8 @@ def getnode():
     if sys.platform == 'win32':
         getters = [_windll_getnode, _netbios_getnode, _ipconfig_getnode]
     else:
-        getters = [_unixdll_getnode, _ifconfig_getnode]
+        getters = [_unixdll_getnode, _ifconfig_getnode, _arp_getnode,
+                   _lanscan_getnode, _netstat_getnode]
 
     for getter in getters + [_random_getnode]:
         try:
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to