Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-libusb1 for openSUSE:Factory 
checked in at 2021-01-20 18:28:17
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-libusb1 (Old)
 and      /work/SRC/openSUSE:Factory/.python-libusb1.new.28504 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-libusb1"

Wed Jan 20 18:28:17 2021 rev:3 rq:864626 version:1.9.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-libusb1/python-libusb1.changes    
2019-05-16 22:09:46.886296749 +0200
+++ /work/SRC/openSUSE:Factory/.python-libusb1.new.28504/python-libusb1.changes 
2021-01-20 18:28:48.571593908 +0100
@@ -1,0 +2,18 @@
+Wed Jan 20 09:43:06 UTC 2021 - John Vandenberg <[email protected]>
+
+- Update to v1.9.1
+  * Fix installation from pypi source tarball, broken in 1.8.1
+- from v1.9
+  * Drop USBPollerThread
+  * Deprecate libusb-lock-related USBContext API
+- from v1.8.1
+  * Embed libusb1 dll for easier deployment on Windows
+  * Cryptographically signed releases
+  * Use libusb_free_pollfds whenever available (libusb1>=1.0.20)
+  * Fix hotplug callback destruction at context teardown
+  * Drop remnants of python 2.6 support code
+- from v1.8
+  * Fix getExtra and libusb1.libusb_control_transfer_get_data
+  * Fix getMaxPower unit on SuperSpeed devices
+
+-------------------------------------------------------------------

Old:
----
  libusb1-1.7.1.tar.gz

New:
----
  libusb1-1.9.1.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-libusb1.spec ++++++
--- /var/tmp/diff_new_pack.eAXzXv/_old  2021-01-20 18:28:49.699594943 +0100
+++ /var/tmp/diff_new_pack.eAXzXv/_new  2021-01-20 18:28:49.703594946 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python-libusb1
 #
-# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2021 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -18,7 +18,7 @@
 
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-libusb1
-Version:        1.7.1
+Version:        1.9.1
 Release:        0
 Summary:        Python wrapper for libusb-1.0
 # Relicensed from GPL to LGPLv2.1+ in May 2015
@@ -40,6 +40,8 @@
 
 %prep
 %setup -q -n libusb1-%{version}
+sed -i '/wheel/d' setup.py
+
 sed -i '1{/^#!/d}' examples/*.py
 chmod a-x examples/*.py
 
@@ -51,7 +53,7 @@
 %python_expand %fdupes %{buildroot}%{$python_sitelib}
 
 %check
-%python_exec -m usb1.testUSB1
+%python_exec -m usb1.testUSB1 -v
 
 %files %{python_files}
 %doc README.rst examples/

++++++ libusb1-1.7.1.tar.gz -> libusb1-1.9.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libusb1-1.7.1/MANIFEST.in 
new/libusb1-1.9.1/MANIFEST.in
--- old/libusb1-1.7.1/MANIFEST.in       2019-05-10 00:49:51.000000000 +0200
+++ new/libusb1-1.9.1/MANIFEST.in       2020-11-29 08:39:10.000000000 +0100
@@ -3,7 +3,7 @@
 include COPYING.LESSER
 include examples/README
 include examples/*.py
-include testUSB1.py
+include usb1/testUSB1.py
 include stdeb.cfg
 include versioneer.py
 include usb1/_version.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libusb1-1.7.1/PKG-INFO new/libusb1-1.9.1/PKG-INFO
--- old/libusb1-1.7.1/PKG-INFO  2019-05-10 00:52:33.000000000 +0200
+++ new/libusb1-1.9.1/PKG-INFO  2020-12-09 14:48:08.651121600 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: libusb1
-Version: 1.7.1
+Version: 1.9.1
 Summary: Pure-python wrapper for libusb-1.0
 Home-page: http://github.com/vpelletier/python-libusb1
 Author: Vincent Pelletier
@@ -452,6 +452,34 @@
         Fix an occasional segfault when closing a transfer from inside its 
callback
         function.
         
+        1.8
+        ---
+        
+        Fix getExtra and libusb1.libusb_control_transfer_get_data .
+        Fix getMaxPower unit on SuperSpeed devices.
+        
+        1.8.1
+        -----
+        
+        Release process rework:
+        
+        - embed libusb1 dll for easier deployment on Windows
+        - cryptographically signed releases
+        
+        Use libusb_free_pollfds whenever available (libusb1>=1.0.20).
+        Fix hotplug callback destruction at context teardown.
+        Drop remnants of python 2.6 support code.
+        
+        1.9
+        ---
+        
+        Drop USBPollerThread and deprecate libusb-lock-related USBContext API.
+        
+        1.9.1
+        -----
+        
+        Fix installation from pypi source tarball, broken in 1.8.1 .
+        
         .. _CPython: http://www.python.org/
         
         .. _pypy: http://pypy.org/
@@ -473,9 +501,6 @@
 Classifier: Intended Audience :: Developers
 Classifier: License :: OSI Approved :: GNU Lesser General Public License v2 or 
later (LGPLv2+)
 Classifier: Operating System :: OS Independent
-Classifier: Programming Language :: Python :: 2.4
-Classifier: Programming Language :: Python :: 2.5
-Classifier: Programming Language :: Python :: 2.6
 Classifier: Programming Language :: Python :: 2.7
 Classifier: Programming Language :: Python :: 3
 Classifier: Programming Language :: Python :: 3.4
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libusb1-1.7.1/README.rst new/libusb1-1.9.1/README.rst
--- old/libusb1-1.7.1/README.rst        2019-05-10 00:49:51.000000000 +0200
+++ new/libusb1-1.9.1/README.rst        2020-12-09 14:47:58.000000000 +0100
@@ -442,6 +442,34 @@
 Fix an occasional segfault when closing a transfer from inside its callback
 function.
 
+1.8
+---
+
+Fix getExtra and libusb1.libusb_control_transfer_get_data .
+Fix getMaxPower unit on SuperSpeed devices.
+
+1.8.1
+-----
+
+Release process rework:
+
+- embed libusb1 dll for easier deployment on Windows
+- cryptographically signed releases
+
+Use libusb_free_pollfds whenever available (libusb1>=1.0.20).
+Fix hotplug callback destruction at context teardown.
+Drop remnants of python 2.6 support code.
+
+1.9
+---
+
+Drop USBPollerThread and deprecate libusb-lock-related USBContext API.
+
+1.9.1
+-----
+
+Fix installation from pypi source tarball, broken in 1.8.1 .
+
 .. _CPython: http://www.python.org/
 
 .. _pypy: http://pypy.org/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libusb1-1.7.1/examples/hotplug_advanced.py 
new/libusb1-1.9.1/examples/hotplug_advanced.py
--- old/libusb1-1.7.1/examples/hotplug_advanced.py      2019-05-10 
00:49:51.000000000 +0200
+++ new/libusb1-1.9.1/examples/hotplug_advanced.py      2020-11-29 
08:39:10.000000000 +0100
@@ -227,7 +227,7 @@
     )
     try:
         mode()
-    except NoHotplugSupport, exc:
+    except NoHotplugSupport as exc:
         print(exc.value)
         sys.exit(1)
     except (KeyboardInterrupt, SystemExit):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libusb1-1.7.1/libusb1.egg-info/PKG-INFO 
new/libusb1-1.9.1/libusb1.egg-info/PKG-INFO
--- old/libusb1-1.7.1/libusb1.egg-info/PKG-INFO 2019-05-10 00:52:33.000000000 
+0200
+++ new/libusb1-1.9.1/libusb1.egg-info/PKG-INFO 2020-12-09 14:48:08.000000000 
+0100
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: libusb1
-Version: 1.7.1
+Version: 1.9.1
 Summary: Pure-python wrapper for libusb-1.0
 Home-page: http://github.com/vpelletier/python-libusb1
 Author: Vincent Pelletier
@@ -452,6 +452,34 @@
         Fix an occasional segfault when closing a transfer from inside its 
callback
         function.
         
+        1.8
+        ---
+        
+        Fix getExtra and libusb1.libusb_control_transfer_get_data .
+        Fix getMaxPower unit on SuperSpeed devices.
+        
+        1.8.1
+        -----
+        
+        Release process rework:
+        
+        - embed libusb1 dll for easier deployment on Windows
+        - cryptographically signed releases
+        
+        Use libusb_free_pollfds whenever available (libusb1>=1.0.20).
+        Fix hotplug callback destruction at context teardown.
+        Drop remnants of python 2.6 support code.
+        
+        1.9
+        ---
+        
+        Drop USBPollerThread and deprecate libusb-lock-related USBContext API.
+        
+        1.9.1
+        -----
+        
+        Fix installation from pypi source tarball, broken in 1.8.1 .
+        
         .. _CPython: http://www.python.org/
         
         .. _pypy: http://pypy.org/
@@ -473,9 +501,6 @@
 Classifier: Intended Audience :: Developers
 Classifier: License :: OSI Approved :: GNU Lesser General Public License v2 or 
later (LGPLv2+)
 Classifier: Operating System :: OS Independent
-Classifier: Programming Language :: Python :: 2.4
-Classifier: Programming Language :: Python :: 2.5
-Classifier: Programming Language :: Python :: 2.6
 Classifier: Programming Language :: Python :: 2.7
 Classifier: Programming Language :: Python :: 3
 Classifier: Programming Language :: Python :: 3.4
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libusb1-1.7.1/setup.py new/libusb1-1.9.1/setup.py
--- old/libusb1-1.7.1/setup.py  2019-05-10 00:49:51.000000000 +0200
+++ new/libusb1-1.9.1/setup.py  2020-12-09 14:47:58.000000000 +0100
@@ -13,30 +13,141 @@
 # You should have received a copy of the GNU Lesser General Public
 # License along with this library; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  
USA
+from __future__ import print_function
 from setuptools import setup
+from setuptools import Command
+import setuptools.command.install
 from codecs import open
+import errno
+import hashlib
 import os
+import subprocess
 import sys
 import versioneer
+try:
+    from urllib.request import urlopen
+    from urllib.parse import urlsplit
+    from html.parser import HTMLParser
+except ImportError:
+    # BBB: python 2.7
+    from urllib2 import urlopen
+    from urlparse import urlsplit
+    from HTMLParser import HTMLParser
+
+if os.getenv('I_KNOW_HOW_TO_RELEASE_PYTHON_LIBUSB1') != '1' and any(
+    x in sys.argv for x in ('sdist', 'upload')
+):
+    print('Use setup.sh to build')
+    sys.exit(1)
+
+CURRENT_WINDOWS_7Z_SHA256 = (
+    'd3087e7d09ec4e463f5f4b394dcfec0b90e835545318af1a75575de59d2dfaac'
+)
+
+cmdclass = versioneer.get_cmdclass()
+class install(setuptools.command.install.install):
+    def run(self):
+        # XXX: setuptools.command.install.install is an old-style class on
+        # python2.7 :(
+        setuptools.command.install.install.run(self)
+        if os.getenv('LIBUSB_BINARY'):
+            self.copy_file(
+                os.getenv('LIBUSB_BINARY'),
+                os.path.join(self.install_lib, 'usb1'),
+            )
+cmdclass['install'] = install
+
+class upload(Command):
+    def run(self):
+        print('This project uses signed releases. See KEYS for instructions.')
+        print('Hint:')
+        print('  twine upload dist/<release file> dist/<release file>.asc')
+        sys.exit(1)
+cmdclass['upload'] = upload
+
+class update_libusb(Command):
+    user_options = []
+
+    def initialize_options(self):
+        pass
+
+    def finalize_options(self):
+        pass
+
+    class WindowsBinariesArchiveLinkFinder(HTMLParser):
+        found = None
+        __a_href = None
+        def handle_starttag(self, tag, attrs):
+            if tag == 'a':
+                assert self.__a_href is None, repr(self.__a_href)
+                self.__a_href = dict(attrs).get('href')
+
+        def handle_endtag(self, tag):
+            if tag == 'a':
+                self.__a_href = None
+
+        def handle_data(self, data):
+            if self.__a_href is not None and data == 'Latest Windows Binaries':
+                assert self.found is None, repr(self.found)
+                self.found = self.__a_href
+
+    def run(self):
+        finder = self.WindowsBinariesArchiveLinkFinder()
+        finder.feed(urlopen('https://libusb.info/').read().decode('utf-8'))
+        finder.close()
+        url = finder.found
+        if url is None:
+            raise ValueError('Failed to locate current windows binary release')
+        build_dir = os.path.join(os.path.dirname(__file__), 'build')
+        download_cache_path = os.path.join(build_dir, 'download-cache')
+        archive_path = os.path.join(
+            download_cache_path,
+            urlsplit(url).path.rsplit('/', 1)[-1],
+        )
+        if not os.path.exists(archive_path):
+            os.makedirs(download_cache_path)
+            with open(archive_path, 'wb') as archive_file:
+                archive_file.write(urlopen(url).read())
+        with open(archive_path, 'rb') as archive_file:
+            archive_sha256 = hashlib.sha256(archive_file.read()).hexdigest()
+        if archive_sha256 != CURRENT_WINDOWS_7Z_SHA256:
+            raise ValueError(
+                'Windows release sha56 mismatch: %r fetched with a sha256 of 
%r' % (
+                    url,
+                    archive_sha256,
+                )
+            )
+        # py2 does not have subprocess.DEVNULL.
+        with open(os.devnull, 'wb') as devnull:
+            for arch_path, out_dir in (
+                ('MS32/dll/libusb-1.0.dll', os.path.join(build_dir, 'win32')),
+                ('MS64/dll/libusb-1.0.dll', os.path.join(build_dir, 
'win_amd64')),
+            ):
+                subprocess.check_call(
+                    [
+                        '7z', 'e', '-aoa',
+                        '-o' + out_dir,
+                        archive_path,
+                        arch_path,
+                    ],
+                    # 7z will not shut its pie hole.
+                    stdout=devnull,
+                    close_fds=True,
+                )
+cmdclass['update_libusb'] = update_libusb
 
 long_description = open(
     os.path.join(os.path.dirname(__file__), 'README.rst'),
     encoding='utf8',
 ).read()
 
-try:
-    next
-except NameError:
-    # "next" builtin missing < 2.6
-    next = lambda x: x.next()
-
 setup(
     name='libusb1',
     description=next(x for x in long_description.splitlines() if x.strip()),
     long_description='.. contents::\n\n' + long_description,
     keywords='usb libusb',
     version=versioneer.get_version(),
-    cmdclass=versioneer.get_cmdclass(),
+    cmdclass=cmdclass,
     author='Vincent Pelletier',
     author_email='[email protected]',
     url='http://github.com/vpelletier/python-libusb1',
@@ -48,9 +159,6 @@
         'Intended Audience :: Developers',
         'License :: OSI Approved :: GNU Lesser General Public License v2 or 
later (LGPLv2+)',
         'Operating System :: OS Independent',
-        'Programming Language :: Python :: 2.4',
-        'Programming Language :: Python :: 2.5',
-        'Programming Language :: Python :: 2.6',
         'Programming Language :: Python :: 2.7',
         'Programming Language :: Python :: 3',
         'Programming Language :: Python :: 3.4',
@@ -62,5 +170,9 @@
         'Topic :: Software Development :: Libraries',
         'Topic :: System :: Hardware :: Hardware Drivers',
     ],
-    use_2to3=sys.version_info >= (3, ),
+    setup_requires=[
+        'wheel',
+    ],
+    use_2to3=True,
+    test_suite='usb1.testUSB1',
 )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libusb1-1.7.1/stdeb.cfg new/libusb1-1.9.1/stdeb.cfg
--- old/libusb1-1.7.1/stdeb.cfg 2016-08-22 01:20:50.000000000 +0200
+++ new/libusb1-1.9.1/stdeb.cfg 2020-11-29 08:39:10.000000000 +0100
@@ -1,4 +1,4 @@
 [DEFAULT]
-Source=python-libusb1
-Package=python-libusb1
+Source=python-usb1
+Package=python-usb1
 Depends=libusb-1.0-0 | libusb2debian
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libusb1-1.7.1/usb1/__init__.py 
new/libusb1-1.9.1/usb1/__init__.py
--- old/libusb1-1.7.1/usb1/__init__.py  2019-05-10 00:49:51.000000000 +0200
+++ new/libusb1-1.9.1/usb1/__init__.py  2020-12-05 03:36:31.000000000 +0100
@@ -53,24 +53,18 @@
 import sys
 import threading
 import warnings
-import weakref
+from weakref import WeakSet
 import collections
 import functools
 import contextlib
 import inspect
 from . import libusb1
-if sys.version_info[:2] >= (2, 6):
 # pylint: disable=wrong-import-order,ungrouped-imports
-    if sys.platform == 'win32':
-        from ctypes import get_last_error as get_errno
-    else:
-        from ctypes import get_errno
-# pylint: enable=wrong-import-order,ungrouped-imports
+if sys.platform == 'win32':
+    from ctypes import get_last_error as get_errno
 else:
-    def get_errno():
-        raise NotImplementedError(
-            'Your python version does not support errno/last_error'
-        )
+    from ctypes import get_errno
+# pylint: enable=wrong-import-order,ungrouped-imports
 
 __all__ = [
     'USBContext', 'USBDeviceHandle', 'USBDevice', 'hasCapability',
@@ -133,15 +127,10 @@
         __raiseUSBError(value)
     return value
 
-try:
-    namedtuple = collections.namedtuple
-except AttributeError:
-    Version = tuple
-else:
-    Version = namedtuple(
-        'Version',
-        ['major', 'minor', 'micro', 'nano', 'rc', 'describe'],
-    )
+Version = collections.namedtuple(
+    'Version',
+    ['major', 'minor', 'micro', 'nano', 'rc', 'describe'],
+)
 
 if sys.version_info[0] == 3:
     BYTE = bytes([0])
@@ -216,29 +205,6 @@
 CONTROL_SETUP = BYTE * CONTROL_SETUP_SIZE
 # pylint: enable=undefined-variable
 
-__libc_name = find_library('c')
-if __libc_name is None:
-    # Of course, will leak memory.
-    # Should we warn user ? How ?
-    _free = lambda x: None
-else:
-    _free = getattr(cdll, __libc_name).free
-del __libc_name
-
-try:
-    WeakSet = weakref.WeakSet
-except AttributeError:
-    # Python < 2.7: tiny wrapper around WeakKeyDictionary
-    class WeakSet(object):
-        def __init__(self):
-            self.__dict = weakref.WeakKeyDictionary()
-
-        def add(self, item):
-            self.__dict[item] = None
-
-        def pop(self):
-            return self.__dict.popitem()[0]
-
 # Default string length
 # From a comment in libusb-1.0: "Some devices choke on size > 255"
 STRING_LENGTH = 255
@@ -945,111 +911,6 @@
         # Deprecated: to drop
         return self.__transfer.isSubmitted()
 
-# BBB
-class USBPollerThread(threading.Thread):
-    """
-    Implements libusb1 documentation about threaded, asynchronous
-    applications.
-    In short, instanciate this class once (...per USBContext instance), call
-    start() on the instance, and do whatever you need.
-    This thread will be used to execute transfer completion callbacks, and you
-    are free to use libusb1's synchronous API in another thread, and can forget
-    about libusb1 file descriptors.
-
-    See http://libusb.sourceforge.net/api-1.0/mtasync.html .
-    """
-    _can_run = True
-
-    def __init__(self, context, poller, exc_callback=None):
-        """
-        Create a poller thread for given context.
-        Warning: it will not check if another poller instance was already
-        present for that context, and will replace it.
-
-        poller
-            (same as USBPoller.__init__ "poller" parameter)
-
-        exc_callback (callable)
-          Called with a libusb_error value as single parameter when event
-          handling fails.
-          If not given, an USBError will be raised, interrupting the thread.
-        """
-        super(USBPollerThread, self).__init__()
-        warnings.warn(
-            'USBPollerThread causes long stalls when used with poll (it was '
-            'intended for epoll), and is generally misleading. Consider '
-            'calling looping over context.handleEvents() in a thread instead.',
-            DeprecationWarning,
-        )
-        self.daemon = True
-        self.__context = context
-        self.__poller = poller
-        self.__fd_set = set()
-        if exc_callback is not None:
-            self.exceptionHandler = exc_callback
-
-    def stop(self):
-        """
-        Stop & join thread.
-
-        Allows stopping event thread before context gets closed.
-        """
-        self._can_run = False
-        self.join()
-
-    # pylint: disable=method-hidden
-    @staticmethod
-    def exceptionHandler(exc):
-        raise exc
-    # pylint: enable=method-hidden
-
-    def run(self):
-        # We expect quite some spinning in below loop, so move any unneeded
-        # operation out of it.
-        context = self.__context
-        poll = self.__poller.poll
-        try_lock_events = context.tryLockEvents
-        lock_event_waiters = context.lockEventWaiters
-        wait_for_event = context.waitForEvent
-        unlock_event_waiters = context.unlockEventWaiters
-        event_handling_ok = context.eventHandlingOK
-        unlock_events = context.unlockEvents
-        handle_events_locked = context.handleEventsLocked
-        event_handler_active = context.eventHandlerActive
-        getNextTimeout = context.getNextTimeout
-        exceptionHandler = self.exceptionHandler
-        fd_set = self.__fd_set
-        context.setPollFDNotifiers(self._registerFD, self._unregisterFD)
-        for fd, events in context.getPollFDList():
-            self._registerFD(fd, events, None)
-        try:
-            while fd_set and self._can_run:
-                if try_lock_events():
-                    lock_event_waiters()
-                    while event_handler_active():
-                        wait_for_event()
-                    unlock_event_waiters()
-                else:
-                    try:
-                        while event_handling_ok():
-                            if poll(getNextTimeout()):
-                                try:
-                                    handle_events_locked()
-                                except USBError:
-                                    exceptionHandler(sys.exc_info()[1])
-                    finally:
-                        unlock_events()
-        finally:
-            context.setPollFDNotifiers(None, None)
-
-    def _registerFD(self, fd, events, _):
-        self.__poller.register(fd, events)
-        self.__fd_set.add(fd)
-
-    def _unregisterFD(self, fd, _):
-        self.__fd_set.discard(fd)
-        self.__poller.unregister(fd)
-
 class USBPoller(object):
     """
     Class allowing integration of USB event polling in a file-descriptor
@@ -1172,7 +1033,6 @@
     # pylint: enable=undefined-variable
     __set = set
     __KeyError = KeyError
-    __sys = sys
 
     def __init__(self, context, handle, device):
         """
@@ -1337,8 +1197,8 @@
         Reinitialise current device.
         Attempts to restore current configuration & alt settings.
         If this fails, will result in a device disconnect & reconnect, so you
-        have to close current device and rediscover it (notified by a
-        ERROR_NOT_FOUND error code).
+        have to close current device and rediscover it (notified by an
+        USBErrorNotFound exception).
         """
         mayRaiseUSBError(libusb1.libusb_reset_device(self.__handle))
 
@@ -1657,7 +1517,7 @@
         return result
 
 class USBConfiguration(object):
-    def __init__(self, context, config):
+    def __init__(self, context, config, device_speed):
         """
         You should not instanciate this class directly.
         Call USBDevice methods to get instances of this class.
@@ -1666,6 +1526,7 @@
             raise TypeError('Unexpected descriptor type.')
         self.__config = config
         self.__context = context
+        self.__device_speed = device_speed
 
     def getNumInterfaces(self):
         return self.__config.bNumInterfaces
@@ -1683,11 +1544,13 @@
 
     def getMaxPower(self):
         """
-        Returns device's power consumption in mW.
-        Beware of unit: USB descriptor uses 2mW increments, this method
-        converts it to mW units.
+        Returns device's power consumption in mA.
+
+        USB descriptor is expressed in units of 2 mA when the device is 
operating in high-speed mode
+        and in units of 8 mA when the device is operating in super-speed mode. 
This function scales
+        the descriptor value appropriately.
         """
-        return self.__config.MaxPower * 2
+        return self.__config.MaxPower * (8 if self.__device_speed == 
SPEED_SUPER else 2)
 
     def getExtra(self):
         """
@@ -1907,6 +1770,9 @@
                     continue
                 mayRaiseUSBError(result)
                 append(config.contents)
+        self.__bus_number = libusb1.libusb_get_bus_number(device_p)
+        self.__port_number = libusb1.libusb_get_port_number(device_p)
+        self.__device_address = libusb1.libusb_get_device_address(device_p)
 
     def __del__(self):
         self.close()
@@ -1945,13 +1811,13 @@
 
     def __getitem__(self, index):
         return USBConfiguration(
-            self.__context, self.__configuration_descriptor_list[index])
+            self.__context, self.__configuration_descriptor_list[index], 
self.getDeviceSpeed())
 
     def __key(self):
         return (
-            id(self.__context), self.getBusNumber(),
-            self.getDeviceAddress(), self.getVendorID(),
-            self.getProductID(),
+            id(self.__context), self.__bus_number,
+            self.__device_address, self.device_descriptor.idVendor,
+            self.device_descriptor.idProduct,
         )
 
     def __hash__(self):
@@ -1970,7 +1836,7 @@
     def iterConfigurations(self):
         context = self.__context
         for config in self.__configuration_descriptor_list:
-            yield USBConfiguration(context, config)
+            yield USBConfiguration(context, config, self.getDeviceSpeed())
 
     # BBB
     iterConfiguations = iterConfigurations
@@ -1985,13 +1851,13 @@
         """
         Get device's bus number.
         """
-        return libusb1.libusb_get_bus_number(self.device_p)
+        return self.__bus_number
 
     def getPortNumber(self):
         """
         Get device's port number.
         """
-        return libusb1.libusb_get_port_number(self.device_p)
+        return self.__port_number
 
     def getPortNumberList(self):
         """
@@ -2010,7 +1876,7 @@
         """
         Get device's address on its bus.
         """
-        return libusb1.libusb_get_device_address(self.device_p)
+        return self.__device_address
 
     def getbcdUSB(self):
         """
@@ -2296,7 +2162,8 @@
     def _exit(self):
         context_p = self.__context_p
         if context_p:
-            for handle in self.__hotplug_callback_dict.keys():
+            while self.__hotplug_callback_dict:
+                handle = next(iter(self.__hotplug_callback_dict))
                 self.hotplugDeregisterCallback(handle)
             pop = self.__close_set.pop
             while True:
@@ -2426,7 +2293,7 @@
                 ))
                 fd_index += 1
         finally:
-            _free(pollfd_p_p)
+            libusb1.libusb_free_pollfds(pollfd_p_p)
         return result
 
     @_validContext
@@ -2520,30 +2387,37 @@
 
     @_validContext
     def tryLockEvents(self):
-        """
-        See libusb_try_lock_events doc.
-        """
+        warnings.warn(
+            'You may not be able to unlock in the event of USBContext exit. '
+            'Consider looping over handleEvents() in a thread.',
+            DeprecationWarning,
+        )
         return libusb1.libusb_try_lock_events(self.__context_p)
 
     @_validContext
     def lockEvents(self):
-        """
-        See libusb_lock_events doc.
-        """
+        warnings.warn(
+            'You may not be able to unlock in the event of USBContext exit. '
+            'Consider looping over handleEvents() in a thread.',
+            DeprecationWarning,
+        )
         libusb1.libusb_lock_events(self.__context_p)
 
     @_validContext
     def lockEventWaiters(self):
-        """
-        See libusb_lock_event_waiters doc.
-        """
+        warnings.warn(
+            'You may not be able to unlock in the event of USBContext exit. '
+            'Consider looping over handleEvents() in a thread.',
+            DeprecationWarning,
+        )
         libusb1.libusb_lock_event_waiters(self.__context_p)
 
     @_validContext
     def waitForEvent(self, tv=0):
-        """
-        See libusb_wait_for_event doc.
-        """
+        warnings.warn(
+            'Consider looping over handleEvents() in a thread.',
+            DeprecationWarning,
+        )
         if tv is None:
             tv = 0
         tv_s = int(tv)
@@ -2552,30 +2426,38 @@
 
     @_validContext
     def unlockEventWaiters(self):
-        """
-        See libusb_unlock_event_waiters doc.
-        """
+        warnings.warn(
+            'This method will lock in the event of USBContext exit, '
+            'preventing libusb lock release. '
+            'Consider looping over handleEvents() in a thread.',
+            DeprecationWarning,
+        )
         libusb1.libusb_unlock_event_waiters(self.__context_p)
 
     @_validContext
     def eventHandlingOK(self):
-        """
-        See libusb_event_handling_ok doc.
-        """
+        warnings.warn(
+            'Consider looping over handleEvents() in a thread.',
+            DeprecationWarning,
+        )
         return libusb1.libusb_event_handling_ok(self.__context_p)
 
     @_validContext
     def unlockEvents(self):
-        """
-        See libusb_unlock_events doc.
-        """
+        warnings.warn(
+            'This method will lock in the event of USBContext exit, '
+            'preventing libusb lock release. '
+            'Consider looping over handleEvents() in a thread.',
+            DeprecationWarning,
+        )
         libusb1.libusb_unlock_events(self.__context_p)
 
     @_validContext
     def handleEventsLocked(self):
-        """
-        See libusb_handle_events_locked doc.
-        """
+        warnings.warn(
+            'Consider looping over handleEvents() in a thread.',
+            DeprecationWarning,
+        )
         # XXX: does tv parameter need to be exposed ?
         mayRaiseUSBError(libusb1.libusb_handle_events_locked(
             self.__context_p, _zero_tv_p,
@@ -2583,9 +2465,10 @@
 
     @_validContext
     def eventHandlerActive(self):
-        """
-        See libusb_event_handler_active doc.
-        """
+        warnings.warn(
+            'Consider looping over handleEvents() in a thread.',
+            DeprecationWarning,
+        )
         return libusb1.libusb_event_handler_active(self.__context_p)
 
     @staticmethod
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libusb1-1.7.1/usb1/_version.py 
new/libusb1-1.9.1/usb1/_version.py
--- old/libusb1-1.7.1/usb1/_version.py  2019-05-10 00:52:33.000000000 +0200
+++ new/libusb1-1.9.1/usb1/_version.py  2020-12-09 14:48:08.655121600 +0100
@@ -9,11 +9,11 @@
 
 version_json = '''
 {
- "date": "2019-05-09T22:49:01+0000",
+ "date": "2020-12-09T13:47:19+0000",
  "dirty": false,
  "error": null,
- "full-revisionid": "4826b68986cf75e7ffb0e7a5ba739eecbddc3cc1",
- "version": "1.7.1"
+ "full-revisionid": "aa6bc1220d9a9bf43745917d3f263426d6624777",
+ "version": "1.9.1"
 }
 '''  # END VERSION_JSON
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libusb1-1.7.1/usb1/libusb1.py 
new/libusb1-1.9.1/usb1/libusb1.py
--- old/libusb1-1.7.1/usb1/libusb1.py   2019-05-10 00:49:51.000000000 +0200
+++ new/libusb1-1.9.1/usb1/libusb1.py   2020-11-29 10:11:16.000000000 +0100
@@ -24,25 +24,14 @@
 Declares all constants, data structures and exported symbols.
 Locates and loads libusb1 dynamic library.
 """
-from ctypes import Structure, LittleEndianStructure, \
-    CFUNCTYPE, POINTER, addressof, sizeof, cast, \
-    c_short, c_int, c_uint, c_size_t, c_long, \
-    c_uint8, c_uint16, c_uint32, \
-    c_void_p, c_char_p, py_object, pointer, c_char
-try:
-    from ctypes import c_ssize_t
-except ImportError:
-    from ctypes import c_longlong
-    # c_ssize_t is new in Python 2.7
-    if sizeof(c_int) == sizeof(c_size_t):
-        c_ssize_t = c_int
-    elif sizeof(c_long) == sizeof(c_size_t):
-        c_ssize_t = c_long
-    elif sizeof(c_longlong) == sizeof(c_size_t):
-        c_ssize_t = c_longlong
-    else:
-        raise ValueError('Unsupported arch: sizeof(c_size_t) = %r' % (
-            sizeof(c_size_t), ))
+from ctypes import (
+    Structure, LittleEndianStructure,
+    CFUNCTYPE, POINTER, addressof, sizeof, cast,
+    c_short, c_int, c_uint, c_size_t, c_long,
+    c_uint8, c_uint16, c_uint32,
+    c_void_p, c_char_p, py_object, pointer, c_char,
+    c_ssize_t, CDLL
+)
 import ctypes.util
 import platform
 import os.path
@@ -140,13 +129,6 @@
         return '%s [%s]' % (libusb_error.get(self.value, 'Unknown error'),
                             self.value)
 
-if sys.version_info[0] == 3:
-    _string_item_to_int = lambda x: x
-    _empty_char_p = bytes()
-else:
-    _string_item_to_int = ord
-    _empty_char_p = ''
-
 c_uchar = c_uint8
 c_int_p = POINTER(c_int)
 
@@ -165,12 +147,14 @@
     else:
         dll_loader = ctypes.CDLL
         suffix = system == 'Darwin' and '.dylib' or '.so'
-    loader_kw = {}
-    if sys.version_info[:2] >= (2, 6):
-        loader_kw['use_errno'] = True
-        loader_kw['use_last_error'] = True
+    filename = 'libusb-1.0' + suffix
+    # If this is a binary wheel, use the integrated libusb unconditionally.
+    # To use the libusb from the Python installation or the OS, install from 
sdist:
+    #   > pip install --no-binary :all: libusb1
+    if os.path.exists(os.path.join(os.path.dirname(__file__), filename)):
+        filename = os.path.join(os.path.dirname(__file__), filename)
     try:
-        return dll_loader('libusb-1.0' + suffix, **loader_kw)
+        return dll_loader(filename, use_errno=True, use_last_error=True)
     except OSError:
         libusb_path = None
         base_name = 'usb-1.0'
@@ -194,7 +178,7 @@
             libusb_path = ctypes.util.find_library(base_name)
             if libusb_path is None:
                 raise
-        return dll_loader(libusb_path, **loader_kw)
+        return dll_loader(libusb_path, use_errno=True, use_last_error=True)
 
 libusb = _loadLibrary()
 
@@ -737,7 +721,7 @@
 try:
     libusb_get_version = libusb.libusb_get_version
 except AttributeError:
-    _dummy_version = libusb_version(0, 0, 0, 0, _empty_char_p, _empty_char_p)
+    _dummy_version = libusb_version(0, 0, 0, 0, b'', b'')
     _dummy_version_p = pointer(_dummy_version)
     def libusb_get_version():
         return _dummy_version_p
@@ -963,7 +947,7 @@
 
 def libusb_control_transfer_get_data(transfer_p):
     transfer = transfer_p.contents
-    return buffer_at(transfer.buffer.value, transfer.length)[
+    return buffer_at(transfer.buffer, transfer.length)[
         LIBUSB_CONTROL_SETUP_SIZE:]
 
 def libusb_control_transfer_get_setup(transfer_p):
@@ -1103,10 +1087,10 @@
     result = []
     extra_length = descriptor.extra_length
     if extra_length:
-        extra = buffer_at(descriptor.extra.value, extra_length)
+        extra = buffer_at(descriptor.extra, extra_length)
         append = result.append
         while extra:
-            length = _string_item_to_int(extra[0])
+            length = extra[0]
             if not 0 < length <= len(extra):
                 raise ValueError(
                     'Extra descriptor %i is incomplete/invalid' % (
@@ -1271,6 +1255,16 @@
                                         libusb_pollfd_added_cb_p,
                                         libusb_pollfd_removed_cb_p, py_object]
 libusb_set_pollfd_notifiers.restype = None
+try:
+    #void libusb_get_pollfds(const struct libusb_pollfd **);
+    libusb_free_pollfds = libusb.libusb_free_pollfds
+    libusb_free_pollfds.argtypes = [libusb_pollfd_p_p]
+    libusb_free_pollfds.restype = None
+except AttributeError:
+    # Not a safe replacement in general, but the versions of libusb that lack
+    # libusb_free_pollfds() only provide that function on *nix, where
+    # Python's free() and libusb's free() are ~always the same anyways.
+    libusb_free_pollfds = CDLL(None).free
 
 #typedef int libusb_hotplug_callback_handle;
 libusb_hotplug_callback_handle = c_int
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libusb1-1.7.1/usb1/testUSB1.py 
new/libusb1-1.9.1/usb1/testUSB1.py
--- old/libusb1-1.7.1/usb1/testUSB1.py  2019-05-10 00:49:51.000000000 +0200
+++ new/libusb1-1.9.1/usb1/testUSB1.py  2020-12-05 03:36:31.000000000 +0100
@@ -18,8 +18,6 @@
 import unittest
 import sys
 import itertools
-import select
-import threading
 import usb1
 import libusb1
 from ctypes import pointer
@@ -43,25 +41,6 @@
                 'usb1.USBContext() fails - no USB bus on system ?'
             )
 
-class PollDetector(object):
-    def __init__(self, *args, **kw):
-        try:
-            poll = select.poll
-        except AttributeError:
-            raise unittest.SkipTest('select.poll missing')
-        self.__poll = poll(*args, **kw)
-        self.__event = threading.Event()
-
-    def poll(self, *args, **kw):
-        self.__event.set()
-        return self.__poll.poll(*args, **kw)
-
-    def wait(self, *args, **kw):
-        self.__event.wait(*args, **kw)
-
-    def __getattr__(self, name):
-        return getattr(self.__poll, name)
-
 class USBTransferTests(unittest.TestCase):
     @staticmethod
     def getTransfer(iso_packets=0):
@@ -200,52 +179,7 @@
         got_callback = transfer.getCallback()
         self.assertEqual(callback, got_callback)
 
-    def testUSBPollerThreadExit(self):
-        """
-        USBPollerThread must exit by itself when context is destroyed.
-        """
-        with USBContext() as context:
-            poll_detector = PollDetector()
-            try:
-                poller = usb1.USBPollerThread(context, poll_detector)
-            except OSError:
-                raise unittest.SkipTest('libusb without file descriptor 
events')
-            poller.start()
-            poll_detector.wait(1)
-        poller.join(1)
-        self.assertFalse(poller.is_alive())
-
-    def testUSBPollerThreadException(self):
-        """
-        USBPollerThread exception handling.
-        """
-        class FakeEventPoll(PollDetector):
-            # pylint: disable=method-hidden
-            def poll(self, *args, **kw):
-                self.poll = super(FakeEventPoll, self).poll
-                return ['dummy']
-            # pylint: enable=method-hidden
-        with USBContext() as context:
-            def fakeHandleEventsLocked():
-                raise usb1.USBError(0)
-            context.handleEventsLocked = fakeHandleEventsLocked
-            exception_event = threading.Event()
-            exception_list = []
-            def exceptionHandler(exc):
-                exception_list.append(exc)
-                exception_event.set()
-            try:
-                poller = usb1.USBPollerThread(
-                    context, FakeEventPoll(), exceptionHandler)
-            except OSError:
-                raise unittest.SkipTest('libusb without file descriptor 
events')
-            poller.start()
-            exception_event.wait(1)
-            self.assertTrue(exception_list, exception_list)
-            self.assertTrue(poller.is_alive())
-
-    @staticmethod
-    def testDescriptors():
+    def _testDescriptors(self, get_extra=False):
         """
         Test descriptor walk.
         Needs any usb device, which won't be opened.
@@ -253,6 +187,7 @@
         with USBContext() as context:
             device_list = context.getDeviceList(skip_on_error=True)
             found = False
+            seen_extra = False
             for device in device_list:
                 device.getBusNumber()
                 device.getPortNumber()
@@ -262,12 +197,26 @@
                     for endpoint in settings:
                         pass
                 for configuration in device.iterConfigurations():
+                    if get_extra and len(configuration.getExtra()) > 0:
+                        seen_extra = True
                     for interface in configuration:
                         for settings in interface:
+                            if get_extra and len(settings.getExtra()) > 0:
+                                seen_extra = True
                             for endpoint in settings:
+                                if get_extra and len(endpoint.getExtra()) > 0:
+                                    seen_extra = True
                                 found = True
             if not found:
                 raise unittest.SkipTest('descriptor walk test did not 
complete')
+            if get_extra and not seen_extra:
+                raise unittest.SkipTest('did not see any extra descriptors')
+
+    def testDescriptors(self):
+        self._testDescriptors()
+
+    def testDescriptorsWithExtra(self):
+        self._testDescriptors(get_extra=True)
 
     def testDefaultEnumScope(self):
         """

Reply via email to