Hello community, here is the log from the commit of package python-pyserial for openSUSE:Factory checked in at 2017-08-12 19:43:24 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-pyserial (Old) and /work/SRC/openSUSE:Factory/.python-pyserial.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-pyserial" Sat Aug 12 19:43:24 2017 rev:15 rq:515045 version:3.4 Changes: -------- --- /work/SRC/openSUSE:Factory/python-pyserial/python-pyserial.changes 2017-06-28 10:33:08.278102490 +0200 +++ /work/SRC/openSUSE:Factory/.python-pyserial.new/python-pyserial.changes 2017-08-12 19:43:25.544109791 +0200 @@ -1,0 +2,26 @@ +Mon Aug 7 16:32:29 UTC 2017 - toddrme2...@gmail.com + +- Further fix shebangs + +------------------------------------------------------------------- +Sun Aug 6 18:07:57 UTC 2017 - toddrme2...@gmail.com + +- Update to version 3.4 + + Improvements: + * miniterm: suspend function (temporarily release port, :kbd:`Ctrl-T s`) + * [#240] context manager automatically opens port on ``__enter__`` + * [#141] list_ports: add interface number to location string + * [#225] protocol_socket: Retry if ``BlockingIOError`` occurs in + ``reset_input_buffer``. + + Bugfixes: + * [#153] list_ports: option to include symlinked devices + * [#237] list_ports: workaround for special characters in port names + + Bugfixes (posix): + * allow calling cancel functions w/o error if port is closed + * [#220] protocol_socket: sync error handling with posix version + * [#227] posix: ignore more blocking errors and EINTR, timeout only + applies to blocking I/O + * [#228] fix: port_publisher typo +- Fix shebangs + +------------------------------------------------------------------- Old: ---- pyserial-3.3.tar.gz New: ---- pyserial-3.4.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-pyserial.spec ++++++ --- /var/tmp/diff_new_pack.LstlaT/_old 2017-08-12 19:43:26.615959450 +0200 +++ /var/tmp/diff_new_pack.LstlaT/_new 2017-08-12 19:43:26.623958328 +0200 @@ -18,7 +18,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-pyserial -Version: 3.3 +Version: 3.4 Release: 0 Url: https://github.com/pyserial/pyserial Summary: Python Serial Port Extension @@ -53,22 +53,43 @@ %prep %setup -q -n pyserial-%{version} -sed -i "s|#\!\/usr\/bin\/env python||" serial/{serialposix,__init__}.py # Fix non-executable scripts +sed -i "s|^#\!\/usr\/bin\/env python$||" serial/{serialposix,__init__}.py # Fix non-executable scripts sed -i "s/\r//" examples/port_publisher.py # Fix EOL encoding +find examples -name '*.py' -exec sed -i "s|^#!/usr/bin/env python$|#!%{__python3}|" {} \; +find examples -name '*.py' -exec sed -i "s|^#! /usr/bin/env python$|#!%{__python3}|" {} \; +find examples -name '*.py' -exec sed -i "s|^#! python$|#!%{__python3}|" {} \; %build %python_build make -C documentation html && rm documentation/_build/html/.buildinfo # Build HTML documentation + %install %python_install -%python_expand %fdupes %{buildroot}%{$python_sitelib} - mv %{buildroot}%{_bindir}/miniterm.py %{buildroot}%{_bindir}/miniterm %python_clone -a %{buildroot}%{_bindir}/miniterm rm documentation/_build/doctrees/environment.pickle +%{python_expand pushd %{buildroot}%{$python_sitelib} +# Fix wrong-script-interpreter +sed -i "s|^#!/usr/bin/env python$|#!%{__$python}|" serial/tools/*.py +sed -i "s|^#!/usr/bin/env python3$|#!%{__$python}|" serial/threaded/__init__.py +sed -i "s|^#!/usr/bin/env python$|#!%{__$python}|" serial/rs485.py +sed -i "s|^#! python$||#!%{__$python}|" serial/tools/*.py +chmod a+x serial/tools/*.py +chmod a-x serial/tools/__init__.py +chmod a-x serial/tools/list_ports_windows.py +chmod a-x serial/tools/hexlify_codec.py +chmod a+x serial/threaded/__init__.py +chmod a+x serial/rs485.py +# Deduplicating files can generate a RPMLINT warning for pyc mtime +$python -m compileall -d %{$python_sitelib} serial/ +$python -O -m compileall -d %{$python_sitelib} serial/ +%fdupes . +popd +} + %post %python_install_alternative miniterm ++++++ pyserial-3.3.tar.gz -> pyserial-3.4.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyserial-3.3/CHANGES.rst new/pyserial-3.4/CHANGES.rst --- old/pyserial-3.3/CHANGES.rst 2017-03-07 23:32:12.000000000 +0100 +++ new/pyserial-3.4/CHANGES.rst 2017-07-22 22:46:46.000000000 +0200 @@ -710,3 +710,27 @@ Bugfixes (win32): - [#194] spurious write fails with ERROR_SUCCESS + + +Version 3.4 2017-07-22 +------------------------ +Improvements: + +- miniterm: suspend function (temporarily release port, :kbd:`Ctrl-T s`) +- [#240] context manager automatically opens port on ``__enter__`` +- [#141] list_ports: add interface number to location string +- [#225] protocol_socket: Retry if ``BlockingIOError`` occurs in + ``reset_input_buffer``. + +Bugfixes: + +- [#153] list_ports: option to include symlinked devices +- [#237] list_ports: workaround for special characters in port names + +Bugfixes (posix): + +- allow calling cancel functions w/o error if port is closed +- [#220] protocol_socket: sync error handling with posix version +- [#227] posix: ignore more blocking errors and EINTR, timeout only + applies to blocking I/O +- [#228] fix: port_publisher typo diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyserial-3.3/PKG-INFO new/pyserial-3.4/PKG-INFO --- old/pyserial-3.3/PKG-INFO 2017-03-08 02:44:53.000000000 +0100 +++ new/pyserial-3.4/PKG-INFO 2017-07-22 22:51:52.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: pyserial -Version: 3.3 +Version: 3.4 Summary: Python Serial Port Extension Home-page: https://github.com/pyserial/pyserial Author: Chris Liechti @@ -35,6 +35,7 @@ Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 Classifier: Topic :: Communications Classifier: Topic :: Software Development :: Libraries Classifier: Topic :: Software Development :: Libraries :: Python Modules diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyserial-3.3/README.rst new/pyserial-3.4/README.rst --- old/pyserial-3.3/README.rst 2016-12-20 23:03:41.000000000 +0100 +++ new/pyserial-3.4/README.rst 2017-03-20 23:20:55.000000000 +0100 @@ -12,7 +12,7 @@ - Project Homepage: https://github.com/pyserial/pyserial - Download Page: https://pypi.python.org/pypi/pyserial -BSD license, (C) 2001-2016 Chris Liechti <cliec...@gmx.net> +BSD license, (C) 2001-2017 Chris Liechti <cliec...@gmx.net> Documentation diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyserial-3.3/documentation/appendix.rst new/pyserial-3.4/documentation/appendix.rst --- old/pyserial-3.3/documentation/appendix.rst 2016-12-13 23:47:25.000000000 +0100 +++ new/pyserial-3.4/documentation/appendix.rst 2017-03-21 00:16:14.000000000 +0100 @@ -68,7 +68,7 @@ used. - :func:`serial.serial_for_url` does a dynamic lookup of protocol handlers - at runtime. If this function is used, the desired handlers have to be + at runtime. If this function is used, the desired handlers have to be included manually (e.g. 'serial.urlhandler.protocol_socket', 'serial.urlhandler.protocol_rfc2217', etc.). This can be done either with the "includes" option in ``setup.py`` or by a dummy import in one of the @@ -93,7 +93,7 @@ Support for Python 2.6 or earlier Support for older Python releases than 2.7 will not return to pySerial 3.x. - Python 2.7 is now many years old (released 2010). If you insist on using + Python 2.7 is now many years old (released 2010). If you insist on using Python 2.6 or earlier, it is recommend to use pySerial `2.7`_ (or any 2.x version). @@ -109,7 +109,7 @@ License ======= -Copyright (c) 2001-2016 Chris Liechti <cliec...@gmx.net> +Copyright (c) 2001-2017 Chris Liechti <cliec...@gmx.net> All Rights Reserved. Redistribution and use in source and binary forms, with or without diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyserial-3.3/documentation/conf.py new/pyserial-3.4/documentation/conf.py --- old/pyserial-3.3/documentation/conf.py 2017-03-07 23:32:00.000000000 +0100 +++ new/pyserial-3.4/documentation/conf.py 2017-07-22 22:49:49.000000000 +0200 @@ -45,9 +45,9 @@ # built documents. # # The short X.Y version. -version = '3.3' +version = '3.4' # The full version, including alpha/beta/rc tags. -release = '3.3' +release = '3.4' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyserial-3.3/documentation/examples.rst new/pyserial-3.4/documentation/examples.rst --- old/pyserial-3.3/documentation/examples.rst 2016-12-20 23:03:41.000000000 +0100 +++ new/pyserial-3.4/documentation/examples.rst 2017-03-21 01:53:38.000000000 +0100 @@ -237,8 +237,10 @@ need a loop back connector. The scripts itself contain more information. All test scripts are contained in the directory ``test``. -The unit tests are performed on port ``0`` unless a different device name or -``rfc2217://`` URL is given on the command line (argv[1]). +The unit tests are performed on port ``loop://`` unless a different device +name or URL is given on the command line (``sys.argv[1]``). e.g. to run the +test on an attached USB-serial converter ``hwgrep://USB`` could be used or +the actual name such as ``/dev/ttyUSB0`` or ``COM1`` (depending on platform). run_all_tests.py_ Collect all tests from all ``test*`` files and run them. By default, the @@ -254,7 +256,7 @@ Tests involving sending a lot of data. test_readline.py_ - Tests involving readline. + Tests involving ``readline``. test_iolib.py_ Tests involving the :mod:`io` library. Only available for Python 2.6 and diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyserial-3.3/documentation/pyserial.rst new/pyserial-3.4/documentation/pyserial.rst --- old/pyserial-3.3/documentation/pyserial.rst 2016-09-18 22:53:26.000000000 +0200 +++ new/pyserial-3.4/documentation/pyserial.rst 2017-03-21 01:36:59.000000000 +0100 @@ -48,7 +48,7 @@ ============ - Python 2.7 or Python 3.4 and newer -- If running on Windows: Something newer than WinXP +- If running on Windows: Windows 7 or newer - If running on Jython: "Java Communications" (JavaComm) or compatible extension for Java @@ -93,7 +93,7 @@ - Debian/Ubuntu: "python-serial", "python3-serial" - Fedora / RHEL / CentOS / EPEL: "pyserial" - Arch Linux: "python-pyserial" -- Gento: "dev-python/pyserial" +- Gentoo: "dev-python/pyserial" Note that some distributions may package an older version of pySerial. These packages are created and maintained by developers working on diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyserial-3.3/documentation/pyserial_api.rst new/pyserial-3.4/documentation/pyserial_api.rst --- old/pyserial-3.3/documentation/pyserial_api.rst 2017-03-07 21:05:02.000000000 +0100 +++ new/pyserial-3.4/documentation/pyserial_api.rst 2017-07-20 23:45:59.000000000 +0200 @@ -122,7 +122,7 @@ Some OS and/or drivers may activate RTS and or DTR automatically, as soon as the port is opened. There may be a glitch on RTS/DTR - when :attr:`rts`` or :attr:`dtr` are set differently from their + when :attr:`rts` or :attr:`dtr` are set differently from their default value (``True`` / active). .. note:: @@ -205,7 +205,7 @@ .. method:: reset_input_buffer() - Flush input buffer, discarding all it's contents. + Flush input buffer, discarding all its contents. .. versionchanged:: 3.0 renamed from ``flushInput()`` @@ -515,17 +515,22 @@ >>> with serial.serial_for_url(port) as s: ... s.write(b'hello') - Here no port argument is given, so it is not opened automatically: + The port is opened automatically: - >>> with serial.Serial() as s: - ... s.port = ... - ... s.open() + >>> port = serial.Serial() + >>> port.port = '...' + >>> with port as s: ... s.write(b'hello') + Which also means that ``with`` statements can be used repeatedly, + each time opening and closing the port. + + .. versionchanged:: 3.4 the port is automatically opened + .. method:: __exit__(exc_type, exc_val, exc_tb) - Closes serial port. + Closes serial port (exceptions are not handled by ``__exit__``). Platform specific methods. @@ -618,7 +623,7 @@ .. method:: isOpen() - .. deprecated:: 3.0 see :attr:`is_open` + .. deprecated:: 3.0 see :attr:`is_open` .. attribute:: writeTimeout @@ -704,6 +709,7 @@ class :class:`SerialBase` and some by the platform specific class and others by the base class mentioned above. + RS485 support ------------- The :class:`Serial` class has a :attr:`Serial.rs485_mode` attribute which allows to @@ -795,7 +801,6 @@ - :rfc:`2217` Network ports ------------------------- @@ -1060,7 +1065,7 @@ :returns: a generator that yields bytes Some versions of Python (3.x) would return integers instead of bytes when - looping over an instance of ``bytes``. This helper function ensures that + looping over an instance of ``bytes``. This helper function ensures that bytes are returned. .. versionadded:: 3.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyserial-3.3/documentation/tools.rst new/pyserial-3.4/documentation/tools.rst --- old/pyserial-3.3/documentation/tools.rst 2016-12-20 23:03:41.000000000 +0100 +++ new/pyserial-3.4/documentation/tools.rst 2017-07-17 23:59:28.000000000 +0200 @@ -12,8 +12,10 @@ serial.tools.list_ports``). It also contains the following functions. -.. function:: comports() +.. function:: comports(include_links=False) + :param bool include_links: include symlinks under ``/dev`` when they point + to a serial port :return: a list containing :class:`ListPortInfo` objects. The function returns a list of :obj:`ListPortInfo` objects. @@ -26,22 +28,36 @@ systems description and hardware ID will not be available (``None``). + Under Linux, OSX and Windows, extended information will be available for + USB devices (e.g. the :attr:`ListPortInfo.hwid` string contains `VID:PID`, + `SER` (serial number), `LOCATION` (hierarchy), which makes them searchable + via :func:`grep`. The USB info is also available as attributes of + :attr:`ListPortInfo`. + + If *include_links* is true, all devices under ``/dev`` are inspected and + tested if they are a link to a known serial port device. These entries + will include ``LINK`` in their ``hwid`` string. This implies that the same + device listed twice, once under its original name and once under linked + name. + :platform: Posix (/dev files) :platform: Linux (/dev files, sysfs) :platform: OSX (iokit) :platform: Windows (setupapi, registry) -.. function:: grep(regexp) +.. function:: grep(regexp, include_links=False) :param regexp: regular expression (see stdlib :mod:`re`) + :param bool include_links: include symlinks under ``/dev`` when they point + to a serial port :return: an iterable that yields :class:`ListPortInfo` objects, see also :func:`comports`. - Search for ports using a regular expression. Port name, description and - hardware ID are searched (case insensitive). The function returns an - iterable that contains the same data that :func:`comports` generates, but - includes only those entries that match the regexp. + Search for ports using a regular expression. Port ``name``, + ``description`` and ``hwid`` are searched (case insensitive). The function + returns an iterable that contains the same data that :func:`comports` + generates, but includes only those entries that match the regexp. .. class:: ListPortInfo @@ -109,18 +125,20 @@ Help for ``python -m serial.tools.list_ports``:: - usage: list_ports.py [-h] [-v] [-q] [-n N] [regexp] + usage: list_ports.py [-h] [-v] [-q] [-n N] [-s] [regexp] Serial port enumeration positional arguments: - regexp only show ports that match this regex + regexp only show ports that match this regex optional arguments: - -h, --help show this help message and exit - -v, --verbose show more messages - -q, --quiet suppress all messages - -n N only output the N-th entry + -h, --help show this help message and exit + -v, --verbose show more messages + -q, --quiet suppress all messages + -n N only output the N-th entry + -s, --include-links include entries that are symlinks to real devices + Examples: @@ -256,6 +274,11 @@ --- x X disable/enable software flow control --- r R disable/enable hardware flow control +:kbd:`Ctrl+T s` suspends the connection (port is opened) and reconnects when a +key is pressed. This can be used to temporarily access the serial port with an +other application, without exiting miniterm. If reconnecting fails it is +also possible to exit (:kbd:`Ctrl+]`) or change the port (:kbd:`p`). + .. versionchanged:: 2.5 Added :kbd:`Ctrl+T` menu and added support for opening URLs. .. versionchanged:: 2.6 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyserial-3.3/documentation/url_handlers.rst new/pyserial-3.4/documentation/url_handlers.rst --- old/pyserial-3.3/documentation/url_handlers.rst 2016-12-20 23:03:41.000000000 +0100 +++ new/pyserial-3.4/documentation/url_handlers.rst 2017-03-18 23:35:49.000000000 +0100 @@ -211,7 +211,8 @@ ``alt://`` ========== -This handler allows to select alternate implementations of the native serial port. +This handler allows to select alternate implementations of the native serial +port. Currently only the POSIX platform provides alternative implementations. @@ -221,10 +222,10 @@ disconnecting while it's in use (e.g. USB-serial unplugged). ``VTIMESerial`` - Implement timeout using ``VTIME``/``VMIN`` of tty device instead of using - ``select``. This means that inter character timeout and overall timeout + Implement timeout using ``VTIME``/``VMIN`` of TTY device instead of using + ``select``. This means that inter character timeout and overall timeout can not be used at the same time. Overall timeout is disabled when - inter-character timeout is used. The error handling is degraded. + inter-character timeout is used. The error handling is degraded. Examples:: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyserial-3.3/examples/port_publisher.py new/pyserial-3.4/examples/port_publisher.py --- old/pyserial-3.3/examples/port_publisher.py 2016-06-21 20:46:49.000000000 +0200 +++ new/pyserial-3.4/examples/port_publisher.py 2017-05-08 23:16:33.000000000 +0200 @@ -465,7 +465,7 @@ if pid > 0: # exit from second parent, save eventual PID before if args.pidfile is not None: - open(args.pidfile, 'w').write("{}".formt(pid)) + open(args.pidfile, 'w').write("{}".format(pid)) sys.exit(0) except OSError as e: log.critical("fork #2 failed: {} ({})\n".format(e.errno, e.strerror)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyserial-3.3/pyserial.egg-info/PKG-INFO new/pyserial-3.4/pyserial.egg-info/PKG-INFO --- old/pyserial-3.3/pyserial.egg-info/PKG-INFO 2017-03-08 02:44:53.000000000 +0100 +++ new/pyserial-3.4/pyserial.egg-info/PKG-INFO 2017-07-22 22:51:51.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: pyserial -Version: 3.3 +Version: 3.4 Summary: Python Serial Port Extension Home-page: https://github.com/pyserial/pyserial Author: Chris Liechti @@ -35,6 +35,7 @@ Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 Classifier: Topic :: Communications Classifier: Topic :: Software Development :: Libraries Classifier: Topic :: Software Development :: Libraries :: Python Modules diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyserial-3.3/pyserial.egg-info/SOURCES.txt new/pyserial-3.4/pyserial.egg-info/SOURCES.txt --- old/pyserial-3.3/pyserial.egg-info/SOURCES.txt 2017-03-08 02:44:53.000000000 +0100 +++ new/pyserial-3.4/pyserial.egg-info/SOURCES.txt 2017-07-22 22:51:51.000000000 +0200 @@ -64,6 +64,7 @@ test/test_advanced.py test/test_asyncio.py test/test_cancel.py +test/test_context.py test/test_exclusive.py test/test_high_load.py test/test_iolib.py diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyserial-3.3/serial/__init__.py new/pyserial-3.4/serial/__init__.py --- old/pyserial-3.3/serial/__init__.py 2017-03-07 23:32:56.000000000 +0100 +++ new/pyserial-3.4/serial/__init__.py 2017-07-22 22:49:29.000000000 +0200 @@ -13,7 +13,7 @@ from serial.serialutil import * #~ SerialBase, SerialException, to_bytes, iterbytes -__version__ = '3.3' +__version__ = '3.4' VERSION = __version__ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyserial-3.3/serial/rfc2217.py new/pyserial-3.4/serial/rfc2217.py --- old/pyserial-3.3/serial/rfc2217.py 2016-12-21 03:19:17.000000000 +0100 +++ new/pyserial-3.4/serial/rfc2217.py 2017-05-03 18:33:25.000000000 +0200 @@ -894,7 +894,7 @@ """\ get last modem state (cached value. If value is "old", request a new one. This cache helps that we don't issue to many requests when e.g. all - status lines, one after the other is queried by the user (getCTS, getDSR + status lines, one after the other is queried by the user (CTS, DSR etc.) """ # active modem state polling enabled? is the value fresh enough? @@ -1009,10 +1009,10 @@ send updates on changes. """ modemstate = ( - (self.serial.getCTS() and MODEMSTATE_MASK_CTS) | - (self.serial.getDSR() and MODEMSTATE_MASK_DSR) | - (self.serial.getRI() and MODEMSTATE_MASK_RI) | - (self.serial.getCD() and MODEMSTATE_MASK_CD)) + (self.serial.cts and MODEMSTATE_MASK_CTS) | + (self.serial.dsr and MODEMSTATE_MASK_DSR) | + (self.serial.ri and MODEMSTATE_MASK_RI) | + (self.serial.cd and MODEMSTATE_MASK_CD)) # check what has changed deltas = modemstate ^ (self.last_modemstate or 0) # when last is None -> 0 if deltas & MODEMSTATE_MASK_CTS: @@ -1234,12 +1234,12 @@ self.logger.warning("requested break state - not implemented") pass # XXX needs cached value elif suboption[2:3] == SET_CONTROL_BREAK_ON: - self.serial.setBreak(True) + self.serial.break_condition = True if self.logger: self.logger.info("changed BREAK to active") self.rfc2217_send_subnegotiation(SERVER_SET_CONTROL, SET_CONTROL_BREAK_ON) elif suboption[2:3] == SET_CONTROL_BREAK_OFF: - self.serial.setBreak(False) + self.serial.break_condition = False if self.logger: self.logger.info("changed BREAK to inactive") self.rfc2217_send_subnegotiation(SERVER_SET_CONTROL, SET_CONTROL_BREAK_OFF) @@ -1248,12 +1248,12 @@ self.logger.warning("requested DTR state - not implemented") pass # XXX needs cached value elif suboption[2:3] == SET_CONTROL_DTR_ON: - self.serial.setDTR(True) + self.serial.dtr = True if self.logger: self.logger.info("changed DTR to active") self.rfc2217_send_subnegotiation(SERVER_SET_CONTROL, SET_CONTROL_DTR_ON) elif suboption[2:3] == SET_CONTROL_DTR_OFF: - self.serial.setDTR(False) + self.serial.dtr = False if self.logger: self.logger.info("changed DTR to inactive") self.rfc2217_send_subnegotiation(SERVER_SET_CONTROL, SET_CONTROL_DTR_OFF) @@ -1263,12 +1263,12 @@ pass # XXX needs cached value #~ self.rfc2217_send_subnegotiation(SERVER_SET_CONTROL, SET_CONTROL_RTS_ON) elif suboption[2:3] == SET_CONTROL_RTS_ON: - self.serial.setRTS(True) + self.serial.rts = True if self.logger: self.logger.info("changed RTS to active") self.rfc2217_send_subnegotiation(SERVER_SET_CONTROL, SET_CONTROL_RTS_ON) elif suboption[2:3] == SET_CONTROL_RTS_OFF: - self.serial.setRTS(False) + self.serial.rts = False if self.logger: self.logger.info("changed RTS to inactive") self.rfc2217_send_subnegotiation(SERVER_SET_CONTROL, SET_CONTROL_RTS_OFF) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyserial-3.3/serial/serialposix.py new/pyserial-3.4/serial/serialposix.py --- old/pyserial-3.3/serial/serialposix.py 2017-03-03 23:36:08.000000000 +0100 +++ new/pyserial-3.4/serial/serialposix.py 2017-07-14 21:49:14.000000000 +0200 @@ -503,24 +503,27 @@ read.extend(buf) except OSError as e: # this is for Python 3.x where select.error is a subclass of - # OSError ignore EAGAIN errors. all other errors are shown - if e.errno != errno.EAGAIN and e.errno != errno.EINTR: + # OSError ignore BlockingIOErrors and EINTR. other errors are shown + # https://www.python.org/dev/peps/pep-0475. + if e.errno not in (errno.EAGAIN, errno.EALREADY, errno.EWOULDBLOCK, errno.EINPROGRESS, errno.EINTR): raise SerialException('read failed: {}'.format(e)) except select.error as e: # this is for Python 2.x - # ignore EAGAIN errors. all other errors are shown + # ignore BlockingIOErrors and EINTR. all errors are shown # see also http://www.python.org/dev/peps/pep-3151/#select - if e[0] != errno.EAGAIN: + if e[0] not in (errno.EAGAIN, errno.EALREADY, errno.EWOULDBLOCK, errno.EINPROGRESS, errno.EINTR): raise SerialException('read failed: {}'.format(e)) if timeout.expired(): break return bytes(read) def cancel_read(self): - os.write(self.pipe_abort_read_w, b"x") + if self.is_open: + os.write(self.pipe_abort_read_w, b"x") def cancel_write(self): - os.write(self.pipe_abort_write_w, b"x") + if self.is_open: + os.write(self.pipe_abort_write_w, b"x") def write(self, data): """Output the given byte string over the serial port.""" @@ -560,12 +563,20 @@ tx_len -= n except SerialException: raise - except OSError as v: - if v.errno != errno.EAGAIN: - raise SerialException('write failed: {}'.format(v)) - # still calculate and check timeout - if timeout.expired(): - raise writeTimeoutError + except OSError as e: + # this is for Python 3.x where select.error is a subclass of + # OSError ignore BlockingIOErrors and EINTR. other errors are shown + # https://www.python.org/dev/peps/pep-0475. + if e.errno not in (errno.EAGAIN, errno.EALREADY, errno.EWOULDBLOCK, errno.EINPROGRESS, errno.EINTR): + raise SerialException('write failed: {}'.format(e)) + except select.error as e: + # this is for Python 2.x + # ignore BlockingIOErrors and EINTR. all errors are shown + # see also http://www.python.org/dev/peps/pep-3151/#select + if e[0] not in (errno.EAGAIN, errno.EALREADY, errno.EWOULDBLOCK, errno.EINPROGRESS, errno.EINTR): + raise SerialException('write failed: {}'.format(e)) + if not timeout.is_non_blocking and timeout.expired(): + raise writeTimeoutError return length - len(d) def flush(self): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyserial-3.3/serial/serialutil.py new/pyserial-3.4/serial/serialutil.py --- old/pyserial-3.3/serial/serialutil.py 2017-03-03 23:36:51.000000000 +0100 +++ new/pyserial-3.4/serial/serialutil.py 2017-07-13 23:31:06.000000000 +0200 @@ -557,6 +557,8 @@ # context manager def __enter__(self): + if not self.is_open: + self.open() return self def __exit__(self, *args, **kwargs): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyserial-3.3/serial/tools/list_ports.py new/pyserial-3.4/serial/tools/list_ports.py --- old/pyserial-3.3/serial/tools/list_ports.py 2016-06-08 06:05:48.000000000 +0200 +++ new/pyserial-3.4/serial/tools/list_ports.py 2017-03-16 23:53:54.000000000 +0100 @@ -34,14 +34,14 @@ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -def grep(regexp): +def grep(regexp, include_links=False): """\ Search for ports using a regular expression. Port name, description and hardware ID are searched. The function returns an iterable that returns the same tuples as comport() would do. """ r = re.compile(regexp, re.I) - for info in comports(): + for info in comports(include_links): port, desc, hwid = info if r.search(port) or r.search(desc) or r.search(hwid): yield info @@ -73,6 +73,11 @@ type=int, help='only output the N-th entry') + parser.add_argument( + '-s', '--include-links', + action='store_true', + help='include entries that are symlinks to real devices') + args = parser.parse_args() hits = 0 @@ -80,9 +85,9 @@ if args.regexp: if not args.quiet: sys.stderr.write("Filtered list with regexp: {!r}\n".format(args.regexp)) - iterator = sorted(grep(args.regexp)) + iterator = sorted(grep(args.regexp, include_links=args.include_links)) else: - iterator = sorted(comports()) + iterator = sorted(comports(include_links=args.include_links)) # list them for n, (port, desc, hwid) in enumerate(iterator, 1): if args.n is None or args.n == n: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyserial-3.3/serial/tools/list_ports_common.py new/pyserial-3.4/serial/tools/list_ports_common.py --- old/pyserial-3.3/serial/tools/list_ports_common.py 2016-08-08 01:08:11.000000000 +0200 +++ new/pyserial-3.4/serial/tools/list_ports_common.py 2017-05-24 03:23:06.000000000 +0200 @@ -8,6 +8,8 @@ # # SPDX-License-Identifier: BSD-3-Clause import re +import glob +import os def numsplit(text): @@ -42,6 +44,9 @@ self.manufacturer = None self.product = None self.interface = None + # special handling for links + if device is not None and os.path.islink(device): + self.hwid = 'LINK={}'.format(os.path.realpath(device)) def usb_description(self): """return a short string to name the port based on USB info""" @@ -86,6 +91,18 @@ raise IndexError('{} > 2'.format(index)) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +def list_links(devices): + """\ + search all /dev devices and look for symlinks to known ports already + listed in devices. + """ + links = [] + for device in glob.glob('/dev/*'): + if os.path.islink(device) and os.path.realpath(device) in devices: + links.append(device) + return links + +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # test if __name__ == '__main__': print(ListPortInfo('dummy')) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyserial-3.3/serial/tools/list_ports_linux.py new/pyserial-3.4/serial/tools/list_ports_linux.py --- old/pyserial-3.3/serial/tools/list_ports_linux.py 2016-06-08 06:05:48.000000000 +0200 +++ new/pyserial-3.4/serial/tools/list_ports_linux.py 2017-05-24 03:23:27.000000000 +0200 @@ -18,6 +18,12 @@ def __init__(self, device): super(SysFS, self).__init__(device) + # special handling for links + if device is not None and os.path.islink(device): + device = os.path.realpath(device) + is_link = True + else: + is_link = False self.name = os.path.basename(device) self.usb_device_path = None if os.path.exists('/sys/class/tty/{}/device'.format(self.name)): @@ -28,17 +34,28 @@ self.subsystem = None # check device type if self.subsystem == 'usb-serial': - self.usb_device_path = os.path.dirname(os.path.dirname(self.device_path)) + self.usb_interface_path = os.path.dirname(self.device_path) elif self.subsystem == 'usb': - self.usb_device_path = os.path.dirname(self.device_path) + self.usb_interface_path = self.device_path else: - self.usb_device_path = None + self.usb_interface_path = None # fill-in info for USB devices - if self.usb_device_path is not None: + if self.usb_interface_path is not None: + self.usb_device_path = os.path.dirname(self.usb_interface_path) + + try: + num_if = int(self.read_line(self.usb_device_path, 'bNumInterfaces')) + except ValueError: + num_if = 1 + self.vid = int(self.read_line(self.usb_device_path, 'idVendor'), 16) self.pid = int(self.read_line(self.usb_device_path, 'idProduct'), 16) self.serial_number = self.read_line(self.usb_device_path, 'serial') - self.location = os.path.basename(self.usb_device_path) + if num_if > 1: # multi interface devices like FT4232 + self.location = os.path.basename(self.usb_interface_path) + else: + self.location = os.path.basename(self.usb_device_path) + self.manufacturer = self.read_line(self.usb_device_path, 'manufacturer') self.product = self.read_line(self.usb_device_path, 'product') self.interface = self.read_line(self.device_path, 'interface') @@ -53,6 +70,9 @@ self.description = self.name self.hwid = os.path.basename(self.device_path) + if is_link: + self.hwid += ' LINK={}'.format(device) + def read_line(self, *args): """\ Helper function to read a single line from a file. @@ -67,12 +87,15 @@ return None -def comports(): +def comports(include_links=False): devices = glob.glob('/dev/ttyS*') # built-in serial ports devices.extend(glob.glob('/dev/ttyUSB*')) # usb-serial with own driver devices.extend(glob.glob('/dev/ttyACM*')) # usb-serial with CDC-ACM profile devices.extend(glob.glob('/dev/ttyAMA*')) # ARM internal port (raspi) devices.extend(glob.glob('/dev/rfcomm*')) # BT serial devices + devices.extend(glob.glob('/dev/ttyAP*')) # Advantech multi-port serial controllers + if include_links: + devices.extend(list_ports_common.list_links(devices)) return [info for info in [SysFS(d) for d in devices] if info.subsystem != "platform"] # hide non-present internal serial ports diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyserial-3.3/serial/tools/list_ports_osx.py new/pyserial-3.4/serial/tools/list_ports_osx.py --- old/pyserial-3.3/serial/tools/list_ports_osx.py 2016-06-08 06:05:48.000000000 +0200 +++ new/pyserial-3.4/serial/tools/list_ports_osx.py 2017-03-17 00:01:23.000000000 +0100 @@ -227,7 +227,8 @@ return None -def comports(): +def comports(include_links=False): + # XXX include_links is currently ignored. are links in /dev even supported here? # Scan for all iokit serial ports services = GetIOServicesByType('IOSerialBSDClient') ports = [] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyserial-3.3/serial/tools/list_ports_posix.py new/pyserial-3.4/serial/tools/list_ports_posix.py --- old/pyserial-3.3/serial/tools/list_ports_posix.py 2016-06-08 06:05:48.000000000 +0200 +++ new/pyserial-3.4/serial/tools/list_ports_posix.py 2017-03-16 23:59:33.000000000 +0100 @@ -34,48 +34,64 @@ # cygwin accepts /dev/com* in many contexts # (such as 'open' call, explicit 'ls'), but 'glob.glob' # and bare 'ls' do not; so use /dev/ttyS* instead - def comports(): + def comports(include_links=False): devices = glob.glob('/dev/ttyS*') + if include_links: + devices.extend(list_ports_common.list_links(devices)) return [list_ports_common.ListPortInfo(d) for d in devices] elif plat[:7] == 'openbsd': # OpenBSD - def comports(): + def comports(include_links=False): devices = glob.glob('/dev/cua*') + if include_links: + devices.extend(list_ports_common.list_links(devices)) return [list_ports_common.ListPortInfo(d) for d in devices] elif plat[:3] == 'bsd' or plat[:7] == 'freebsd': - def comports(): + def comports(include_links=False): devices = glob.glob('/dev/cua*[!.init][!.lock]') + if include_links: + devices.extend(list_ports_common.list_links(devices)) return [list_ports_common.ListPortInfo(d) for d in devices] elif plat[:6] == 'netbsd': # NetBSD - def comports(): + def comports(include_links=False): """scan for available ports. return a list of device names.""" devices = glob.glob('/dev/dty*') + if include_links: + devices.extend(list_ports_common.list_links(devices)) return [list_ports_common.ListPortInfo(d) for d in devices] elif plat[:4] == 'irix': # IRIX - def comports(): + def comports(include_links=False): """scan for available ports. return a list of device names.""" devices = glob.glob('/dev/ttyf*') + if include_links: + devices.extend(list_ports_common.list_links(devices)) return [list_ports_common.ListPortInfo(d) for d in devices] elif plat[:2] == 'hp': # HP-UX (not tested) - def comports(): + def comports(include_links=False): """scan for available ports. return a list of device names.""" devices = glob.glob('/dev/tty*p0') + if include_links: + devices.extend(list_ports_common.list_links(devices)) return [list_ports_common.ListPortInfo(d) for d in devices] elif plat[:5] == 'sunos': # Solaris/SunOS - def comports(): + def comports(include_links=False): """scan for available ports. return a list of device names.""" devices = glob.glob('/dev/tty*c') + if include_links: + devices.extend(list_ports_common.list_links(devices)) return [list_ports_common.ListPortInfo(d) for d in devices] elif plat[:3] == 'aix': # AIX - def comports(): + def comports(include_links=False): """scan for available ports. return a list of device names.""" devices = glob.glob('/dev/tty*') + if include_links: + devices.extend(list_ports_common.list_links(devices)) return [list_ports_common.ListPortInfo(d) for d in devices] else: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyserial-3.3/serial/tools/list_ports_windows.py new/pyserial-3.4/serial/tools/list_ports_windows.py --- old/pyserial-3.3/serial/tools/list_ports_windows.py 2016-10-28 21:46:08.000000000 +0200 +++ new/pyserial-3.4/serial/tools/list_ports_windows.py 2017-05-24 03:34:50.000000000 +0200 @@ -143,6 +143,7 @@ # repeat for all possible GUIDs for index in range(guids_size.value): + bInterfaceNumber = None g_hdi = SetupDiGetClassDevs( ctypes.byref(GUIDs[index]), None, @@ -210,13 +211,15 @@ # in case of USB, make a more readable string, similar to that form # that we also generate on other platforms if szHardwareID_str.startswith('USB'): - m = re.search(r'VID_([0-9a-f]{4})(&PID_([0-9a-f]{4}))?(\\(\w+))?', szHardwareID_str, re.I) + m = re.search(r'VID_([0-9a-f]{4})(&PID_([0-9a-f]{4}))?(&MI_(\d{2}))?(\\(\w+))?', szHardwareID_str, re.I) if m: info.vid = int(m.group(1), 16) if m.group(3): info.pid = int(m.group(3), 16) if m.group(5): - info.serial_number = m.group(5) + bInterfaceNumber = int(m.group(5)) + if m.group(7): + info.serial_number = m.group(7) # calculate a location string loc_path_str = ctypes.create_unicode_buffer(250) if SetupDiGetDeviceRegistryProperty( @@ -238,6 +241,10 @@ else: location.append('-') location.append(g.group(2)) + if bInterfaceNumber is not None: + location.append(':{}.{}'.format( + 'x', # XXX how to determine correct bConfigurationValue? + bInterfaceNumber)) if location: info.location = ''.join(location) info.hwid = info.usb_info() @@ -287,7 +294,7 @@ SetupDiDestroyDeviceInfoList(g_hdi) -def comports(): +def comports(include_links=False): """Return a list of info objects about serial ports""" return list(iterate_comports()) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyserial-3.3/serial/tools/miniterm.py new/pyserial-3.4/serial/tools/miniterm.py --- old/pyserial-3.3/serial/tools/miniterm.py 2016-12-06 04:10:38.000000000 +0100 +++ new/pyserial-3.4/serial/tools/miniterm.py 2017-07-19 22:57:17.000000000 +0200 @@ -315,7 +315,7 @@ sys.stderr.write('\n--- Available ports:\n') ports = [] for n, (port, desc, hwid) in enumerate(sorted(comports()), 1): - sys.stderr.write('--- {:2}: {:20} {}\n'.format(n, port, desc)) + sys.stderr.write('--- {:2}: {:20} {!r}\n'.format(n, port, desc)) ports.append(port) while True: port = raw_input('--- Enter port index or full name: ') @@ -502,25 +502,7 @@ if self.echo: self.console.write(c) elif c == '\x15': # CTRL+U -> upload file - sys.stderr.write('\n--- File to upload: ') - sys.stderr.flush() - with self.console: - filename = sys.stdin.readline().rstrip('\r\n') - if filename: - try: - with open(filename, 'rb') as f: - sys.stderr.write('--- Sending file {} ---\n'.format(filename)) - while True: - block = f.read(1024) - if not block: - break - self.serial.write(block) - # Wait for output buffer to drain. - self.serial.flush() - sys.stderr.write('.') # Progress indicator. - sys.stderr.write('\n--- File {} sent ---\n'.format(filename)) - except IOError as e: - sys.stderr.write('--- ERROR opening file {}: {} ---\n'.format(filename, e)) + self.upload_file() elif c in '\x08hH?': # CTRL+H, h, H, ? -> Show help sys.stderr.write(self.get_help_text()) elif c == '\x12': # CTRL+R -> Toggle RTS @@ -536,22 +518,7 @@ self.echo = not self.echo sys.stderr.write('--- local echo {} ---\n'.format('active' if self.echo else 'inactive')) elif c == '\x06': # CTRL+F -> edit filters - sys.stderr.write('\n--- Available Filters:\n') - sys.stderr.write('\n'.join( - '--- {:<10} = {.__doc__}'.format(k, v) - for k, v in sorted(TRANSFORMATIONS.items()))) - sys.stderr.write('\n--- Enter new filter name(s) [{}]: '.format(' '.join(self.filters))) - with self.console: - new_filters = sys.stdin.readline().lower().split() - if new_filters: - for f in new_filters: - if f not in TRANSFORMATIONS: - sys.stderr.write('--- unknown filter: {}\n'.format(repr(f))) - break - else: - self.filters = new_filters - self.update_transformations() - sys.stderr.write('--- filters: {}\n'.format(' '.join(self.filters))) + self.change_filter() elif c == '\x0c': # CTRL+L -> EOL mode modes = list(EOL_TRANSFORMATIONS) # keys eol = modes.index(self.eol) + 1 @@ -561,63 +528,17 @@ sys.stderr.write('--- EOL: {} ---\n'.format(self.eol.upper())) self.update_transformations() elif c == '\x01': # CTRL+A -> set encoding - sys.stderr.write('\n--- Enter new encoding name [{}]: '.format(self.input_encoding)) - with self.console: - new_encoding = sys.stdin.readline().strip() - if new_encoding: - try: - codecs.lookup(new_encoding) - except LookupError: - sys.stderr.write('--- invalid encoding name: {}\n'.format(new_encoding)) - else: - self.set_rx_encoding(new_encoding) - self.set_tx_encoding(new_encoding) - sys.stderr.write('--- serial input encoding: {}\n'.format(self.input_encoding)) - sys.stderr.write('--- serial output encoding: {}\n'.format(self.output_encoding)) + self.change_encoding() elif c == '\x09': # CTRL+I -> info self.dump_port_settings() #~ elif c == '\x01': # CTRL+A -> cycle escape mode #~ elif c == '\x0c': # CTRL+L -> cycle linefeed mode elif c in 'pP': # P -> change port - with self.console: - try: - port = ask_for_port() - except KeyboardInterrupt: - port = None - if port and port != self.serial.port: - # reader thread needs to be shut down - self._stop_reader() - # save settings - settings = self.serial.getSettingsDict() - try: - new_serial = serial.serial_for_url(port, do_not_open=True) - # restore settings and open - new_serial.applySettingsDict(settings) - new_serial.rts = self.serial.rts - new_serial.dtr = self.serial.dtr - new_serial.open() - new_serial.break_condition = self.serial.break_condition - except Exception as e: - sys.stderr.write('--- ERROR opening new port: {} ---\n'.format(e)) - new_serial.close() - else: - self.serial.close() - self.serial = new_serial - sys.stderr.write('--- Port changed to: {} ---\n'.format(self.serial.port)) - # and restart the reader thread - self._start_reader() + self.change_port() + elif c in 'sS': # S -> suspend / open port temporarily + self.suspend_port() elif c in 'bB': # B -> change baudrate - sys.stderr.write('\n--- Baudrate: ') - sys.stderr.flush() - with self.console: - backup = self.serial.baudrate - try: - self.serial.baudrate = int(sys.stdin.readline().strip()) - except ValueError as e: - sys.stderr.write('--- ERROR setting baudrate: {} ---\n'.format(e)) - self.serial.baudrate = backup - else: - self.dump_port_settings() + self.change_baudrate() elif c == '8': # 8 -> change to 8 bits self.serial.bytesize = serial.EIGHTBITS self.dump_port_settings() @@ -657,6 +578,138 @@ else: sys.stderr.write('--- unknown menu character {} --\n'.format(key_description(c))) + def upload_file(self): + """Ask user for filenname and send its contents""" + sys.stderr.write('\n--- File to upload: ') + sys.stderr.flush() + with self.console: + filename = sys.stdin.readline().rstrip('\r\n') + if filename: + try: + with open(filename, 'rb') as f: + sys.stderr.write('--- Sending file {} ---\n'.format(filename)) + while True: + block = f.read(1024) + if not block: + break + self.serial.write(block) + # Wait for output buffer to drain. + self.serial.flush() + sys.stderr.write('.') # Progress indicator. + sys.stderr.write('\n--- File {} sent ---\n'.format(filename)) + except IOError as e: + sys.stderr.write('--- ERROR opening file {}: {} ---\n'.format(filename, e)) + + def change_filter(self): + """change the i/o transformations""" + sys.stderr.write('\n--- Available Filters:\n') + sys.stderr.write('\n'.join( + '--- {:<10} = {.__doc__}'.format(k, v) + for k, v in sorted(TRANSFORMATIONS.items()))) + sys.stderr.write('\n--- Enter new filter name(s) [{}]: '.format(' '.join(self.filters))) + with self.console: + new_filters = sys.stdin.readline().lower().split() + if new_filters: + for f in new_filters: + if f not in TRANSFORMATIONS: + sys.stderr.write('--- unknown filter: {}\n'.format(repr(f))) + break + else: + self.filters = new_filters + self.update_transformations() + sys.stderr.write('--- filters: {}\n'.format(' '.join(self.filters))) + + def change_encoding(self): + """change encoding on the serial port""" + sys.stderr.write('\n--- Enter new encoding name [{}]: '.format(self.input_encoding)) + with self.console: + new_encoding = sys.stdin.readline().strip() + if new_encoding: + try: + codecs.lookup(new_encoding) + except LookupError: + sys.stderr.write('--- invalid encoding name: {}\n'.format(new_encoding)) + else: + self.set_rx_encoding(new_encoding) + self.set_tx_encoding(new_encoding) + sys.stderr.write('--- serial input encoding: {}\n'.format(self.input_encoding)) + sys.stderr.write('--- serial output encoding: {}\n'.format(self.output_encoding)) + + def change_baudrate(self): + """change the baudrate""" + sys.stderr.write('\n--- Baudrate: ') + sys.stderr.flush() + with self.console: + backup = self.serial.baudrate + try: + self.serial.baudrate = int(sys.stdin.readline().strip()) + except ValueError as e: + sys.stderr.write('--- ERROR setting baudrate: {} ---\n'.format(e)) + self.serial.baudrate = backup + else: + self.dump_port_settings() + + def change_port(self): + """Have a conversation with the user to change the serial port""" + with self.console: + try: + port = ask_for_port() + except KeyboardInterrupt: + port = None + if port and port != self.serial.port: + # reader thread needs to be shut down + self._stop_reader() + # save settings + settings = self.serial.getSettingsDict() + try: + new_serial = serial.serial_for_url(port, do_not_open=True) + # restore settings and open + new_serial.applySettingsDict(settings) + new_serial.rts = self.serial.rts + new_serial.dtr = self.serial.dtr + new_serial.open() + new_serial.break_condition = self.serial.break_condition + except Exception as e: + sys.stderr.write('--- ERROR opening new port: {} ---\n'.format(e)) + new_serial.close() + else: + self.serial.close() + self.serial = new_serial + sys.stderr.write('--- Port changed to: {} ---\n'.format(self.serial.port)) + # and restart the reader thread + self._start_reader() + + def suspend_port(self): + """\ + open port temporarily, allow reconnect, exit and port change to get + out of the loop + """ + # reader thread needs to be shut down + self._stop_reader() + self.serial.close() + sys.stderr.write('\n--- Port closed: {} ---\n'.format(self.serial.port)) + do_change_port = False + while not self.serial.is_open: + sys.stderr.write('--- Quit: {exit} | p: port change | any other key to reconnect ---\n'.format( + exit=key_description(self.exit_character))) + k = self.console.getkey() + if k == self.exit_character: + self.stop() # exit app + break + elif k in 'pP': + do_change_port = True + break + try: + self.serial.open() + except Exception as e: + sys.stderr.write('--- ERROR opening port: {} ---\n'.format(e)) + if do_change_port: + self.change_port() + else: + # and restart the reader thread + self._start_reader() + sys.stderr.write('--- Port opened: {} ---\n'.format(self.serial.port)) + def get_help_text(self): """return the help text""" # help text, starts with blank line! diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyserial-3.3/serial/urlhandler/protocol_socket.py new/pyserial-3.4/serial/urlhandler/protocol_socket.py --- old/pyserial-3.3/serial/urlhandler/protocol_socket.py 2016-12-18 06:20:07.000000000 +0100 +++ new/pyserial-3.4/serial/urlhandler/protocol_socket.py 2017-05-06 23:16:12.000000000 +0200 @@ -170,14 +170,15 @@ read.extend(buf) except OSError as e: # this is for Python 3.x where select.error is a subclass of - # OSError ignore EAGAIN errors. all other errors are shown - if e.errno != errno.EAGAIN: + # OSError ignore BlockingIOErrors and EINTR. other errors are shown + # https://www.python.org/dev/peps/pep-0475. + if e.errno not in (errno.EAGAIN, errno.EALREADY, errno.EWOULDBLOCK, errno.EINPROGRESS, errno.EINTR): raise SerialException('read failed: {}'.format(e)) except (select.error, socket.error) as e: # this is for Python 2.x - # ignore EAGAIN errors. all other errors are shown + # ignore BlockingIOErrors and EINTR. all errors are shown # see also http://www.python.org/dev/peps/pep-3151/#select - if e[0] != errno.EAGAIN: + if e[0] not in (errno.EAGAIN, errno.EALREADY, errno.EWOULDBLOCK, errno.EINPROGRESS, errno.EINTR): raise SerialException('read failed: {}'.format(e)) if timeout.expired(): break @@ -220,12 +221,20 @@ tx_len -= n except SerialException: raise - except OSError as v: - if v.errno != errno.EAGAIN: - raise SerialException('write failed: {}'.format(v)) - # still calculate and check timeout - if timeout.expired(): - raise writeTimeoutError + except OSError as e: + # this is for Python 3.x where select.error is a subclass of + # OSError ignore BlockingIOErrors and EINTR. other errors are shown + # https://www.python.org/dev/peps/pep-0475. + if e.errno not in (errno.EAGAIN, errno.EALREADY, errno.EWOULDBLOCK, errno.EINPROGRESS, errno.EINTR): + raise SerialException('write failed: {}'.format(e)) + except select.error as e: + # this is for Python 2.x + # ignore BlockingIOErrors and EINTR. all errors are shown + # see also http://www.python.org/dev/peps/pep-3151/#select + if e[0] not in (errno.EAGAIN, errno.EALREADY, errno.EWOULDBLOCK, errno.EINPROGRESS, errno.EINTR): + raise SerialException('write failed: {}'.format(e)) + if not timeout.is_non_blocking and timeout.expired(): + raise writeTimeoutError return length - len(d) def reset_input_buffer(self): @@ -241,15 +250,16 @@ self._socket.recv(4096) except OSError as e: # this is for Python 3.x where select.error is a subclass of - # OSError ignore EAGAIN errors. all other errors are shown - if e.errno != errno.EAGAIN: - raise SerialException('reset_input_buffer failed: {}'.format(e)) + # OSError ignore BlockingIOErrors and EINTR. other errors are shown + # https://www.python.org/dev/peps/pep-0475. + if e.errno not in (errno.EAGAIN, errno.EALREADY, errno.EWOULDBLOCK, errno.EINPROGRESS, errno.EINTR): + raise SerialException('read failed: {}'.format(e)) except (select.error, socket.error) as e: # this is for Python 2.x - # ignore EAGAIN errors. all other errors are shown + # ignore BlockingIOErrors and EINTR. all errors are shown # see also http://www.python.org/dev/peps/pep-3151/#select - if e[0] != errno.EAGAIN: - raise SerialException('reset_input_buffer failed: {}'.format(e)) + if e[0] not in (errno.EAGAIN, errno.EALREADY, errno.EWOULDBLOCK, errno.EINPROGRESS, errno.EINTR): + raise SerialException('read failed: {}'.format(e)) def reset_output_buffer(self): """\ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyserial-3.3/setup.cfg new/pyserial-3.4/setup.cfg --- old/pyserial-3.3/setup.cfg 2017-03-08 02:44:53.000000000 +0100 +++ new/pyserial-3.4/setup.cfg 2017-07-22 22:51:52.000000000 +0200 @@ -6,7 +6,6 @@ ignore = E265, E126, E241 [egg_info] -tag_svn_revision = 0 -tag_date = 0 tag_build = +tag_date = 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyserial-3.3/setup.py new/pyserial-3.4/setup.py --- old/pyserial-3.3/setup.py 2016-06-18 21:41:56.000000000 +0200 +++ new/pyserial-3.4/setup.py 2017-03-20 23:21:15.000000000 +0100 @@ -6,7 +6,7 @@ # For Python 3.x use the corresponding Python executable, # e.g. "python3 setup.py ..." # -# (C) 2001-2016 Chris Liechti <cliec...@gmx.net> +# (C) 2001-2017 Chris Liechti <cliec...@gmx.net> # # SPDX-License-Identifier: BSD-3-Clause import io @@ -89,6 +89,7 @@ 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', 'Topic :: Communications', 'Topic :: Software Development :: Libraries', 'Topic :: Software Development :: Libraries :: Python Modules', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyserial-3.3/test/test_context.py new/pyserial-3.4/test/test_context.py --- old/pyserial-3.3/test/test_context.py 1970-01-01 01:00:00.000000000 +0100 +++ new/pyserial-3.4/test/test_context.py 2017-07-13 23:31:06.000000000 +0200 @@ -0,0 +1,49 @@ +#! /usr/bin/env python +# +# This file is part of pySerial - Cross platform serial port support for Python +# (C) 2017 Guillaume Galeazzi <guillaum...@leazzi.ch> +# +# SPDX-License-Identifier: BSD-3-Clause +"""\ +Some tests for the serial module. +Part of pySerial (http://pyserial.sf.net) (C)2001-2011 cliec...@gmx.net + +Intended to be run on different platforms, to ensure portability of +the code. + +Cover some of the aspects of context managment +""" + +import unittest +import serial + +# on which port should the tests be performed: +PORT = 'loop://' + + +class Test_Context(unittest.TestCase): + """Test context""" + + def setUp(self): + # create a closed serial port + self.s = serial.serial_for_url(PORT) + + def tearDown(self): + self.s.close() + + def test_with_idempotent(self): + with self.s as stream: + stream.write(b'1234') + + # do other stuff like calling an exe which use COM4 + + with self.s as stream: + stream.write(b'5678') + + +if __name__ == '__main__': + import sys + sys.stdout.write(__doc__) + sys.argv[1:] = ['-v'] + # When this module is executed from the command-line, it runs all its tests + unittest.main() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyserial-3.3/test/test_pty.py new/pyserial-3.4/test/test_pty.py --- old/pyserial-3.3/test/test_pty.py 2016-05-10 23:47:12.000000000 +0200 +++ new/pyserial-3.4/test/test_pty.py 2017-05-03 18:33:25.000000000 +0200 @@ -18,6 +18,7 @@ import unittest import serial +DATA = b'Hello\n' @unittest.skipIf(pty is None, "pty module not supported on platform") class Test_Pty_Serial_Open(unittest.TestCase): @@ -27,11 +28,50 @@ # Open PTY self.master, self.slave = pty.openpty() - def test_pty_serial_open(self): - """Open serial port on slave""" - ser = serial.Serial(os.ttyname(self.slave)) - ser.close() - + def test_pty_serial_open_slave(self): + with serial.Serial(os.ttyname(self.slave), timeout=1) as slave: + pass # OK + + def test_pty_serial_write(self): + with serial.Serial(os.ttyname(self.slave), timeout=1) as slave: + with os.fdopen(self.master, "wb") as fd: + fd.write(DATA) + fd.flush() + out = slave.read(len(DATA)) + self.assertEqual(DATA, out) + + def test_pty_serial_read(self): + with serial.Serial(os.ttyname(self.slave), timeout=1) as slave: + with os.fdopen(self.master, "rb") as fd: + slave.write(DATA) + slave.flush() + out = fd.read(len(DATA)) + self.assertEqual(DATA, out) + + #~ def test_pty_serial_master_read(self): + #~ with serial.Serial(os.ttyname(self.master), timeout=1) as master: + #~ with os.fdopen(self.slave, "wb") as fd: + #~ fd.write(DATA) + #~ fd.flush() + #~ out = master.read(len(DATA)) + #~ self.assertEqual(DATA, out) + + #~ def test_pty_serial_master_write(self): + #~ with serial.Serial(os.ttyname(self.master), timeout=1) as master: + #~ with os.fdopen(self.slave, "rb") as fd: + #~ master.write(DATA) + #~ master.flush() + #~ out = fd.read(len(DATA)) + #~ self.assertEqual(DATA, out) + + #~ def test_pty_bidirectional(self): + #~ with serial.Serial(os.ttyname(self.master), timeout=1) as master: + #~ with serial.Serial(os.ttyname(self.slave), timeout=1) as slave: + #~ with os.fdopen(self.master, "rb") as fd: + #~ master.write(DATA) + #~ master.flush() + #~ out = slave.read(len(DATA)) + #~ self.assertEqual(DATA, out) if __name__ == '__main__': sys.stdout.write(__doc__)