Merge branch 'master' into 326-miniterm.py-exclusive-access
diff --git a/documentation/pyserial.rst b/documentation/pyserial.rst
index adec998..8a1afa8 100644
--- a/documentation/pyserial.rst
+++ b/documentation/pyserial.rst
@@ -86,7 +86,7 @@
     
     conda install -c conda-forge pyserial
     
-Currently the default conda channel will provide version 2.7 whereas the
+Currently the default conda channel will provide version 3.4 whereas the
 conda-forge channel provides the current 3.x version.
 
 Conda: https://www.continuum.io/downloads
diff --git a/documentation/shortintro.rst b/documentation/shortintro.rst
index 02385d9..b9230e3 100644
--- a/documentation/shortintro.rst
+++ b/documentation/shortintro.rst
@@ -108,5 +108,5 @@
 Accessing ports
 ---------------
 pySerial includes a small console based terminal program called
-:ref:`miniterm`.  It ca be started with ``python -m serial.tools.miniterm <port_name>``
+:ref:`miniterm`.  It can be started with ``python -m serial.tools.miniterm <port_name>``
 (use option ``-h`` to get a listing of all options).
diff --git a/serial/__init__.py b/serial/__init__.py
index c24ced8..dcd7c12 100644
--- a/serial/__init__.py
+++ b/serial/__init__.py
@@ -7,6 +7,8 @@
 #
 # SPDX-License-Identifier:    BSD-3-Clause
 
+from __future__ import absolute_import
+
 import sys
 import importlib
 
diff --git a/serial/rfc2217.py b/serial/rfc2217.py
index e8ddb7f..d962c1e 100644
--- a/serial/rfc2217.py
+++ b/serial/rfc2217.py
@@ -58,6 +58,8 @@
 #   RFC).
 # the order of the options is not relevant
 
+from __future__ import absolute_import
+
 import logging
 import socket
 import struct
@@ -613,7 +615,10 @@
             while len(data) < size:
                 if self._thread is None:
                     raise SerialException('connection failed (reader thread died)')
-                data += self._read_buffer.get(True, timeout.time_left())
+                buf = self._read_buffer.get(True, timeout.time_left())
+                if buf is None:
+                    return bytes(data)
+                data += buf
                 if timeout.expired():
                     break
         except Queue.Empty:  # -> timeout
@@ -738,8 +743,10 @@
                     # connection fails -> terminate loop
                     if self.logger:
                         self.logger.debug("socket error in reader thread: {}".format(e))
+                    self._read_buffer.put(None)
                     break
                 if not data:
+                    self._read_buffer.put(None)
                     break  # lost connection
                 for byte in iterbytes(data):
                     if mode == M_NORMAL:
diff --git a/serial/rs485.py b/serial/rs485.py
index 2939350..d7aff6f 100644
--- a/serial/rs485.py
+++ b/serial/rs485.py
@@ -13,6 +13,8 @@
 NOTE: Some implementations may only support a subset of the settings.
 """
 
+from __future__ import absolute_import
+
 import time
 import serial
 
diff --git a/serial/serialcli.py b/serial/serialcli.py
index 0727a52..ddd0cdf 100644
--- a/serial/serialcli.py
+++ b/serial/serialcli.py
@@ -7,6 +7,8 @@
 #
 # SPDX-License-Identifier:    BSD-3-Clause
 
+from __future__ import absolute_import
+
 import System
 import System.IO.Ports
 from serial.serialutil import *
diff --git a/serial/serialjava.py b/serial/serialjava.py
index 7bd5b3e..9c920c5 100644
--- a/serial/serialjava.py
+++ b/serial/serialjava.py
@@ -7,6 +7,8 @@
 #
 # SPDX-License-Identifier:    BSD-3-Clause
 
+from __future__ import absolute_import
+
 from serial.serialutil import *
 
 
diff --git a/serial/serialposix.py b/serial/serialposix.py
index 3ac6283..82fe59a 100644
--- a/serial/serialposix.py
+++ b/serial/serialposix.py
@@ -26,6 +26,8 @@
 # - aix (AIX)               /dev/tty%d
 
 
+from __future__ import absolute_import
+
 # pylint: disable=abstract-method
 import errno
 import fcntl
diff --git a/serial/serialutil.py b/serial/serialutil.py
index 7d51752..e847a6a 100644
--- a/serial/serialutil.py
+++ b/serial/serialutil.py
@@ -7,6 +7,8 @@
 #
 # SPDX-License-Identifier:    BSD-3-Clause
 
+from __future__ import absolute_import
+
 import io
 import time
 
diff --git a/serial/serialwin32.py b/serial/serialwin32.py
index 7b88999..74bfd05 100644
--- a/serial/serialwin32.py
+++ b/serial/serialwin32.py
@@ -9,6 +9,8 @@
 #
 # Initial patch to use ctypes by Giovanni Bajo <rasky@develer.com>
 
+from __future__ import absolute_import
+
 # pylint: disable=invalid-name,too-few-public-methods
 import ctypes
 import time
diff --git a/serial/threaded/__init__.py b/serial/threaded/__init__.py
index 74b6924..9b8fa01 100644
--- a/serial/threaded/__init__.py
+++ b/serial/threaded/__init__.py
@@ -9,6 +9,8 @@
 """\
 Support threading with serial ports.
 """
+from __future__ import absolute_import
+
 import serial
 import threading
 
diff --git a/serial/tools/hexlify_codec.py b/serial/tools/hexlify_codec.py
index 1371da2..bd8f6b0 100644
--- a/serial/tools/hexlify_codec.py
+++ b/serial/tools/hexlify_codec.py
@@ -18,6 +18,8 @@
 
 """
 
+from __future__ import absolute_import
+
 import codecs
 import serial
 
diff --git a/serial/tools/list_ports.py b/serial/tools/list_ports.py
index 827e81f..0d7e3d4 100644
--- a/serial/tools/list_ports.py
+++ b/serial/tools/list_ports.py
@@ -16,6 +16,8 @@
 based on their descriptions or hardware ID.
 """
 
+from __future__ import absolute_import
+
 import sys
 import os
 import re
diff --git a/serial/tools/list_ports_common.py b/serial/tools/list_ports_common.py
index aa91e5e..122e0a2 100644
--- a/serial/tools/list_ports_common.py
+++ b/serial/tools/list_ports_common.py
@@ -7,6 +7,9 @@
 # (C) 2015 Chris Liechti <cliechti@gmx.net>
 #
 # SPDX-License-Identifier:    BSD-3-Clause
+
+from __future__ import absolute_import
+
 import re
 import glob
 import os
@@ -32,7 +35,7 @@
 class ListPortInfo(object):
     """Info collection base class for serial ports"""
 
-    def __init__(self, device=None):
+    def __init__(self, device, skip_link_detection=False):
         self.device = device
         self.name = os.path.basename(device)
         self.description = 'n/a'
@@ -46,7 +49,7 @@
         self.product = None
         self.interface = None
         # special handling for links
-        if device is not None and os.path.islink(device):
+        if not skip_link_detection and device is not None and os.path.islink(device):
             self.hwid = 'LINK={}'.format(os.path.realpath(device))
 
     def usb_description(self):
@@ -91,6 +94,7 @@
         else:
             raise IndexError('{} > 2'.format(index))
 
+
 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 def list_links(devices):
     """\
@@ -103,6 +107,7 @@
             links.append(device)
     return links
 
+
 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 # test
 if __name__ == '__main__':
diff --git a/serial/tools/list_ports_linux.py b/serial/tools/list_ports_linux.py
index 4ee7877..3f7eadb 100644
--- a/serial/tools/list_ports_linux.py
+++ b/serial/tools/list_ports_linux.py
@@ -8,6 +8,8 @@
 #
 # SPDX-License-Identifier:    BSD-3-Clause
 
+from __future__ import absolute_import
+
 import glob
 import os
 from serial.tools import list_ports_common
diff --git a/serial/tools/list_ports_osx.py b/serial/tools/list_ports_osx.py
index 79ce4f1..f46a820 100644
--- a/serial/tools/list_ports_osx.py
+++ b/serial/tools/list_ports_osx.py
@@ -21,6 +21,8 @@
 
 # Also see the 'IORegistryExplorer' for an idea of what we are actually searching
 
+from __future__ import absolute_import
+
 import ctypes
 import ctypes.util
 
diff --git a/serial/tools/list_ports_posix.py b/serial/tools/list_ports_posix.py
index 0d580b0..79bc8ed 100644
--- a/serial/tools/list_ports_posix.py
+++ b/serial/tools/list_ports_posix.py
@@ -16,6 +16,8 @@
 currently just identical to the port name.
 """
 
+from __future__ import absolute_import
+
 import glob
 import sys
 import os
diff --git a/serial/tools/list_ports_windows.py b/serial/tools/list_ports_windows.py
index f28047b..19b9499 100644
--- a/serial/tools/list_ports_windows.py
+++ b/serial/tools/list_ports_windows.py
@@ -8,6 +8,8 @@
 #
 # SPDX-License-Identifier:    BSD-3-Clause
 
+from __future__ import absolute_import
+
 # pylint: disable=invalid-name,too-few-public-methods
 import re
 import ctypes
@@ -113,7 +115,7 @@
 RegCloseKey.restype = LONG
 
 RegQueryValueEx = advapi32.RegQueryValueExW
-RegQueryValueEx.argtypes = [HKEY, LPCTSTR , LPDWORD, LPDWORD, LPBYTE, LPDWORD]
+RegQueryValueEx.argtypes = [HKEY, LPCTSTR, LPDWORD, LPDWORD, LPBYTE, LPDWORD]
 RegQueryValueEx.restype = LONG
 
 
@@ -206,7 +208,7 @@
             # stringify
             szHardwareID_str = szHardwareID.value
 
-            info = list_ports_common.ListPortInfo(port_name_buffer.value)
+            info = list_ports_common.ListPortInfo(port_name_buffer.value, skip_link_detection=True)
 
             # in case of USB, make a more readable string, similar to that form
             # that we also generate on other platforms
diff --git a/serial/tools/miniterm.py b/serial/tools/miniterm.py
index b2d4adb..3b8d5d2 100644
--- a/serial/tools/miniterm.py
+++ b/serial/tools/miniterm.py
@@ -3,10 +3,12 @@
 # Very simple serial terminal
 #
 # This file is part of pySerial. https://github.com/pyserial/pyserial
-# (C)2002-2015 Chris Liechti <cliechti@gmx.net>
+# (C)2002-2017 Chris Liechti <cliechti@gmx.net>
 #
 # SPDX-License-Identifier:    BSD-3-Clause
 
+from __future__ import absolute_import
+
 import codecs
 import os
 import sys
@@ -347,8 +349,8 @@
         self.eol = eol
         self.filters = filters
         self.update_transformations()
-        self.exit_character = 0x1d  # GS/CTRL+]
-        self.menu_character = 0x14  # Menu: CTRL+T
+        self.exit_character = unichr(0x1d)  # GS/CTRL+]
+        self.menu_character = unichr(0x14)  # Menu: CTRL+T
         self.alive = None
         self._reader_alive = None
         self.receiver_thread = None
@@ -520,7 +522,7 @@
         elif c == '\x06':                       # CTRL+F -> edit filters
             self.change_filter()
         elif c == '\x0c':                       # CTRL+L -> EOL mode
-            modes = list(EOL_TRANSFORMATIONS)  # keys
+            modes = list(EOL_TRANSFORMATIONS)   # keys
             eol = modes.index(self.eol) + 1
             if eol >= len(modes):
                 eol = 0
@@ -760,130 +762,130 @@
     import argparse
 
     parser = argparse.ArgumentParser(
-        description="Miniterm - A simple terminal program for the serial port.")
+        description='Miniterm - A simple terminal program for the serial port.')
 
     parser.add_argument(
-        "port",
+        'port',
         nargs='?',
-        help="serial port name ('-' to show port list)",
+        help='serial port name ("-" to show port list)',
         default=default_port)
 
     parser.add_argument(
-        "baudrate",
+        'baudrate',
         nargs='?',
         type=int,
-        help="set baud rate, default: %(default)s",
+        help='set baud rate, default: %(default)s',
         default=default_baudrate)
 
-    group = parser.add_argument_group("port settings")
+    group = parser.add_argument_group('port settings')
 
     group.add_argument(
-        "--parity",
+        '--parity',
         choices=['N', 'E', 'O', 'S', 'M'],
         type=lambda c: c.upper(),
-        help="set parity, one of {N E O S M}, default: N",
+        help='set parity, one of {N E O S M}, default: N',
         default='N')
 
     group.add_argument(
-        "--rtscts",
-        action="store_true",
-        help="enable RTS/CTS flow control (default off)",
+        '--rtscts',
+        action='store_true',
+        help='enable RTS/CTS flow control (default off)',
         default=False)
 
     group.add_argument(
-        "--xonxoff",
-        action="store_true",
-        help="enable software flow control (default off)",
+        '--xonxoff',
+        action='store_true',
+        help='enable software flow control (default off)',
         default=False)
 
     group.add_argument(
-        "--rts",
+        '--rts',
         type=int,
-        help="set initial RTS line state (possible values: 0, 1)",
+        help='set initial RTS line state (possible values: 0, 1)',
         default=default_rts)
 
     group.add_argument(
-        "--dtr",
+        '--dtr',
         type=int,
-        help="set initial DTR line state (possible values: 0, 1)",
+        help='set initial DTR line state (possible values: 0, 1)',
         default=default_dtr)
 
     group.add_argument(
-        "--non-exclusive",
-        dest="exclusive",
-        action="store_false",
-        help="disable locking for native ports",
+        '--non-exclusive',
+        dest='exclusive',
+        action='store_false',
+        help='disable locking for native ports',
         default=True)
 
     group.add_argument(
-        "--ask",
-        action="store_true",
-        help="ask again for port when open fails",
+        '--ask',
+        action='store_true',
+        help='ask again for port when open fails',
         default=False)
 
-    group = parser.add_argument_group("data handling")
+    group = parser.add_argument_group('data handling')
 
     group.add_argument(
-        "-e", "--echo",
-        action="store_true",
-        help="enable local echo (default off)",
+        '-e', '--echo',
+        action='store_true',
+        help='enable local echo (default off)',
         default=False)
 
     group.add_argument(
-        "--encoding",
-        dest="serial_port_encoding",
-        metavar="CODEC",
-        help="set the encoding for the serial port (e.g. hexlify, Latin1, UTF-8), default: %(default)s",
+        '--encoding',
+        dest='serial_port_encoding',
+        metavar='CODEC',
+        help='set the encoding for the serial port (e.g. hexlify, Latin1, UTF-8), default: %(default)s',
         default='UTF-8')
 
     group.add_argument(
-        "-f", "--filter",
-        action="append",
-        metavar="NAME",
-        help="add text transformation",
+        '-f', '--filter',
+        action='append',
+        metavar='NAME',
+        help='add text transformation',
         default=[])
 
     group.add_argument(
-        "--eol",
+        '--eol',
         choices=['CR', 'LF', 'CRLF'],
         type=lambda c: c.upper(),
-        help="end of line mode",
+        help='end of line mode',
         default='CRLF')
 
     group.add_argument(
-        "--raw",
-        action="store_true",
-        help="Do no apply any encodings/transformations",
+        '--raw',
+        action='store_true',
+        help='Do no apply any encodings/transformations',
         default=False)
 
-    group = parser.add_argument_group("hotkeys")
+    group = parser.add_argument_group('hotkeys')
 
     group.add_argument(
-        "--exit-char",
+        '--exit-char',
         type=int,
         metavar='NUM',
-        help="Unicode of special character that is used to exit the application, default: %(default)s",
+        help='Unicode of special character that is used to exit the application, default: %(default)s',
         default=0x1d)  # GS/CTRL+]
 
     group.add_argument(
-        "--menu-char",
+        '--menu-char',
         type=int,
         metavar='NUM',
-        help="Unicode code of special character that is used to control miniterm (menu), default: %(default)s",
+        help='Unicode code of special character that is used to control miniterm (menu), default: %(default)s',
         default=0x14)  # Menu: CTRL+T
 
-    group = parser.add_argument_group("diagnostics")
+    group = parser.add_argument_group('diagnostics')
 
     group.add_argument(
-        "-q", "--quiet",
-        action="store_true",
-        help="suppress non-error messages",
+        '-q', '--quiet',
+        action='store_true',
+        help='suppress non-error messages',
         default=False)
 
     group.add_argument(
-        "--develop",
-        action="store_true",
-        help="show Python traceback on error",
+        '--develop',
+        action='store_true',
+        help='show Python traceback on error',
         default=False)
 
     args = parser.parse_args()
@@ -977,7 +979,7 @@
     except KeyboardInterrupt:
         pass
     if not args.quiet:
-        sys.stderr.write("\n--- exit ---\n")
+        sys.stderr.write('\n--- exit ---\n')
     miniterm.join()
     miniterm.close()
 
diff --git a/serial/urlhandler/protocol_alt.py b/serial/urlhandler/protocol_alt.py
index c14a87e..2e666ca 100644
--- a/serial/urlhandler/protocol_alt.py
+++ b/serial/urlhandler/protocol_alt.py
@@ -16,6 +16,8 @@
 #   use poll based implementation on Posix (Linux):
 #   python -m serial.tools.miniterm alt:///dev/ttyUSB0?class=PosixPollSerial
 
+from __future__ import absolute_import
+
 try:
     import urlparse
 except ImportError:
diff --git a/serial/urlhandler/protocol_hwgrep.py b/serial/urlhandler/protocol_hwgrep.py
index 49bbebe..1a288c9 100644
--- a/serial/urlhandler/protocol_hwgrep.py
+++ b/serial/urlhandler/protocol_hwgrep.py
@@ -20,6 +20,8 @@
 # n=<N>     pick the N'th entry instead of the first one (numbering starts at 1)
 # skip_busy tries to open port to check if it is busy, fails on posix as ports are not locked!
 
+from __future__ import absolute_import
+
 import serial
 import serial.tools.list_ports
 
diff --git a/serial/urlhandler/protocol_loop.py b/serial/urlhandler/protocol_loop.py
index 7bf6cf9..985e7a7 100644
--- a/serial/urlhandler/protocol_loop.py
+++ b/serial/urlhandler/protocol_loop.py
@@ -13,6 +13,8 @@
 # URL format:    loop://[option[/option...]]
 # options:
 # - "debug" print diagnostic messages
+from __future__ import absolute_import
+
 import logging
 import numbers
 import time
diff --git a/serial/urlhandler/protocol_rfc2217.py b/serial/urlhandler/protocol_rfc2217.py
index 1898803..8be310f 100644
--- a/serial/urlhandler/protocol_rfc2217.py
+++ b/serial/urlhandler/protocol_rfc2217.py
@@ -7,4 +7,6 @@
 #
 # SPDX-License-Identifier:    BSD-3-Clause
 
+from __future__ import absolute_import
+
 from serial.rfc2217 import Serial  # noqa
diff --git a/serial/urlhandler/protocol_socket.py b/serial/urlhandler/protocol_socket.py
index 5c77415..36cdf1f 100644
--- a/serial/urlhandler/protocol_socket.py
+++ b/serial/urlhandler/protocol_socket.py
@@ -16,6 +16,8 @@
 # options:
 # - "debug" print diagnostic messages
 
+from __future__ import absolute_import
+
 import errno
 import logging
 import select
diff --git a/serial/urlhandler/protocol_spy.py b/serial/urlhandler/protocol_spy.py
index 3479010..92aaa2e 100644
--- a/serial/urlhandler/protocol_spy.py
+++ b/serial/urlhandler/protocol_spy.py
@@ -20,6 +20,8 @@
 #   redirect output to an other terminal window on Posix (Linux):
 #   python -m serial.tools.miniterm spy:///dev/ttyUSB0?dev=/dev/pts/14\&color
 
+from __future__ import absolute_import
+
 import sys
 import time
 
diff --git a/serial/win32.py b/serial/win32.py
index 905ce0f..08b6e67 100644
--- a/serial/win32.py
+++ b/serial/win32.py
@@ -9,6 +9,8 @@
 
 # pylint: disable=invalid-name,too-few-public-methods,protected-access,too-many-instance-attributes
 
+from __future__ import absolute_import
+
 from ctypes import c_ulong, c_void_p, c_int64, c_char, \
                    WinDLL, sizeof, Structure, Union, POINTER
 from ctypes.wintypes import HANDLE