gurudesh/pytracebugs huggingface dataset:
# Buggy code
def __init__(self, *args, **kwargs):
    self.__dict__["tracks"] = tuple(kwargs.pop("tracks", []))
    self.__dict__["artists"] = tuple(kwargs.pop("artists", []))
    self.__dict__["albums"] = tuple(kwargs.pop("albums", []))
    super(SearchResult, self).__init__(*args, **kwargs)


# Traceback (TypeError)
erik@faust:~$  mopidy
Traceback (most recent call last):
File "/usr/local/bin/mopidy", line 5, in <module>
main()
File "/usr/local/lib64/python2.6/site-packages/mopidy/__main__.py", line 48, in main
options = parse_options()
File "/usr/local/lib64/python2.6/site-packages/mopidy/__main__.py", line 85, in parse_options
help='show GStreamer help options')
File "/usr/lib64/python2.6/optparse.py", line 1012, in add_option
raise TypeError, "invalid arguments"
TypeError: invalid arguments
erik@faust:~$  python --version
Python 2.6
erik@faust:~$  uname -a
Linux faust 3.0.13-0.27-default #1 SMP Wed Feb 15 13:33:49 UTC 2012 (d73692b) x86_64 x86_64 x86_64 GNU/Linux
erik@faust:~$  cat /etc/SuSE-release
SUSE Linux Enterprise Server 11 (x86_64)
VERSION = 11
PATCHLEVEL = 2
erik@faust:~$

# Fixed code
def __init__(self, *args, **kwargs):
    # NOTE kwargs dict keys must be bytestrings to work on Python < 2.6.5
    # See https://github.com/mopidy/mopidy/issues/302 for details
    self.__dict__[b"tracks"] = tuple(kwargs.pop("tracks", []))
    self.__dict__[b"artists"] = tuple(kwargs.pop("artists", []))
    self.__dict__[b"albums"] = tuple(kwargs.pop("albums", []))
    super(SearchResult, self).__init__(*args, **kwargs)
# Buggy code
def parse_options():
    parser = optparse.OptionParser(version="Mopidy %s" % versioning.get_version())
    # NOTE Python 2.6: To support Python versions < 2.6.2rc1 we must use
    # bytestrings for the first argument to ``add_option``
    # See https://github.com/mopidy/mopidy/issues/302 for details
    parser.add_option(
        b"-q",
        "--quiet",
        action="store_const",
        const=0,
        dest="verbosity_level",
        help="less output (warning level)",
    )
    parser.add_option(
        b"-v",
        "--verbose",
        action="count",
        default=1,
        dest="verbosity_level",
        help="more output (debug level)",
    )
    return parser.parse_args(args=mopidy_args)[0]


# Traceback (TypeError)
erik@faust:~$  mopidy
Traceback (most recent call last):
File "/usr/local/bin/mopidy", line 5, in <module>
main()
File "/usr/local/lib64/python2.6/site-packages/mopidy/__main__.py", line 48, in main
options = parse_options()
File "/usr/local/lib64/python2.6/site-packages/mopidy/__main__.py", line 85, in parse_options
help='show GStreamer help options')
File "/usr/lib64/python2.6/optparse.py", line 1012, in add_option
raise TypeError, "invalid arguments"
TypeError: invalid arguments
erik@faust:~$  python --version
Python 2.6
erik@faust:~$  uname -a
Linux faust 3.0.13-0.27-default #1 SMP Wed Feb 15 13:33:49 UTC 2012 (d73692b) x86_64 x86_64 x86_64 GNU/Linux
erik@faust:~$  cat /etc/SuSE-release
SUSE Linux Enterprise Server 11 (x86_64)
VERSION = 11
PATCHLEVEL = 2
erik@faust:~$

# Fixed code
def parse_options():
    parser = optparse.OptionParser(version="Mopidy %s" % versioning.get_version())
    # NOTE First argument to add_option must be bytestrings on Python < 2.6.2
    # See https://github.com/mopidy/mopidy/issues/302 for details
    parser.add_option(
        b"-q",
        "--quiet",
        action="store_const",
        const=0,
        dest="verbosity_level",
        help="less output (warning level)",
    )
    parser.add_option(
        b"-v",
        "--verbose",
        action="count",
        default=1,
        dest="verbosity_level",
        help="more output (debug level)",
    )
    return parser.parse_args(args=mopidy_args)[0]
# Buggy code
def model_json_decoder(dct):
    """
    Automatically deserialize Mopidy models from JSON.

    Usage::

        >>> import json
        >>> json.loads(
        ...     '{"a_track": {"__model__": "Track", "name": "name"}}',
        ...     object_hook=model_json_decoder)
        {u'a_track': Track(artists=[], name=u'name')}

    """
    if "__model__" in dct:
        model_name = dct.pop("__model__")
        cls = globals().get(model_name, None)
        if issubclass(cls, ImmutableObject):
            return cls(**dct)
    return dct


# Traceback (TypeError)
erik@faust:~$  mopidy
Traceback (most recent call last):
File "/usr/local/bin/mopidy", line 5, in <module>
main()
File "/usr/local/lib64/python2.6/site-packages/mopidy/__main__.py", line 48, in main
options = parse_options()
File "/usr/local/lib64/python2.6/site-packages/mopidy/__main__.py", line 85, in parse_options
help='show GStreamer help options')
File "/usr/lib64/python2.6/optparse.py", line 1012, in add_option
raise TypeError, "invalid arguments"
TypeError: invalid arguments
erik@faust:~$  python --version
Python 2.6
erik@faust:~$  uname -a
Linux faust 3.0.13-0.27-default #1 SMP Wed Feb 15 13:33:49 UTC 2012 (d73692b) x86_64 x86_64 x86_64 GNU/Linux
erik@faust:~$  cat /etc/SuSE-release
SUSE Linux Enterprise Server 11 (x86_64)
VERSION = 11
PATCHLEVEL = 2
erik@faust:~$

# Fixed code
def model_json_decoder(dct):
    """
    Automatically deserialize Mopidy models from JSON.

    Usage::

        >>> import json
        >>> json.loads(
        ...     '{"a_track": {"__model__": "Track", "name": "name"}}',
        ...     object_hook=model_json_decoder)
        {u'a_track': Track(artists=[], name=u'name')}

    """
    # NOTE kwargs dict keys must be bytestrings to work on Python < 2.6.5
    # See https://github.com/mopidy/mopidy/issues/302 for details.
    if "__model__" in dct:
        model_name = dct.pop("__model__")
        cls = globals().get(model_name, None)
        if issubclass(cls, ImmutableObject):
            kwargs = {}
            for key, value in dct.items():
                kwargs[str(key)] = value
            return cls(**kwargs)
    return dct
# Buggy code
def __init__(self, config, core):
    super(MpdFrontend, self).__init__()
    hostname = network.format_hostname(config["mpd"]["hostname"])
    port = config["mpd"]["port"]

    # NOTE kwargs dict keys must be bytestrings to work on Python < 2.6.5
    # See https://github.com/mopidy/mopidy/issues/302 for details.
    try:
        network.Server(
            hostname,
            port,
            protocol=session.MpdSession,
            protocol_kwargs={
                b"config": config,
                b"core": core,
            },
            max_connections=config["mpd"]["max_connections"],
            timeout=config["mpd"]["connection_timeout"],
        )
    except IOError as error:
        logger.error("MPD server startup failed: %s", encoding.locale_decode(error))
        sys.exit(1)

    logger.info("MPD server running at [%s]:%s", hostname, port)


# Traceback (TypeError)
erik@faust:~$  mopidy
Traceback (most recent call last):
File "/usr/local/bin/mopidy", line 5, in <module>
main()
File "/usr/local/lib64/python2.6/site-packages/mopidy/__main__.py", line 48, in main
options = parse_options()
File "/usr/local/lib64/python2.6/site-packages/mopidy/__main__.py", line 85, in parse_options
help='show GStreamer help options')
File "/usr/lib64/python2.6/optparse.py", line 1012, in add_option
raise TypeError, "invalid arguments"
TypeError: invalid arguments
erik@faust:~$  python --version
Python 2.6
erik@faust:~$  uname -a
Linux faust 3.0.13-0.27-default #1 SMP Wed Feb 15 13:33:49 UTC 2012 (d73692b) x86_64 x86_64 x86_64 GNU/Linux
erik@faust:~$  cat /etc/SuSE-release
SUSE Linux Enterprise Server 11 (x86_64)
VERSION = 11
PATCHLEVEL = 2
erik@faust:~$

# Fixed code
def __init__(self, config, core):
    super(MpdFrontend, self).__init__()
    hostname = network.format_hostname(config["mpd"]["hostname"])
    port = config["mpd"]["port"]

    try:
        network.Server(
            hostname,
            port,
            protocol=session.MpdSession,
            protocol_kwargs={
                "config": config,
                "core": core,
            },
            max_connections=config["mpd"]["max_connections"],
            timeout=config["mpd"]["connection_timeout"],
        )
    except IOError as error:
        logger.error("MPD server startup failed: %s", encoding.locale_decode(error))
        sys.exit(1)

    logger.info("MPD server running at [%s]:%s", hostname, port)
# Buggy code
def decorator(func):
    match = re.search("([a-z_]+)", pattern)
    if match is not None:
        mpd_commands.add(MpdCommand(name=match.group(), auth_required=auth_required))
    # NOTE Make pattern a bytestring to get bytestring keys in the dict
    # returned from matches.groupdict(), which is again used as a **kwargs
    # dict. This is needed to work on Python < 2.6.5.
    # See https://github.com/mopidy/mopidy/issues/302 for details.
    bytestring_pattern = pattern.encode("utf-8")
    compiled_pattern = re.compile(bytestring_pattern, flags=re.UNICODE)
    if compiled_pattern in request_handlers:
        raise ValueError("Tried to redefine handler for %s with %s" % (pattern, func))
    request_handlers[compiled_pattern] = func
    func.__doc__ = "    - *Pattern:* ``%s``\n\n%s" % (pattern, func.__doc__ or "")
    return func


# Traceback (TypeError)
erik@faust:~$  mopidy
Traceback (most recent call last):
File "/usr/local/bin/mopidy", line 5, in <module>
main()
File "/usr/local/lib64/python2.6/site-packages/mopidy/__main__.py", line 48, in main
options = parse_options()
File "/usr/local/lib64/python2.6/site-packages/mopidy/__main__.py", line 85, in parse_options
help='show GStreamer help options')
File "/usr/lib64/python2.6/optparse.py", line 1012, in add_option
raise TypeError, "invalid arguments"
TypeError: invalid arguments
erik@faust:~$  python --version
Python 2.6
erik@faust:~$  uname -a
Linux faust 3.0.13-0.27-default #1 SMP Wed Feb 15 13:33:49 UTC 2012 (d73692b) x86_64 x86_64 x86_64 GNU/Linux
erik@faust:~$  cat /etc/SuSE-release
SUSE Linux Enterprise Server 11 (x86_64)
VERSION = 11
PATCHLEVEL = 2
erik@faust:~$

# Fixed code
def decorator(func):
    match = re.search("([a-z_]+)", pattern)
    if match is not None:
        mpd_commands.add(MpdCommand(name=match.group(), auth_required=auth_required))
    compiled_pattern = re.compile(pattern, flags=re.UNICODE)
    if compiled_pattern in request_handlers:
        raise ValueError("Tried to redefine handler for %s with %s" % (pattern, func))
    request_handlers[compiled_pattern] = func
    func.__doc__ = "    - *Pattern:* ``%s``\n\n%s" % (pattern, func.__doc__ or "")
    return func
# Buggy code
def copy(self, **values):
    """
    Copy the model with ``field`` updated to new value.

    Examples::

        # Returns a track with a new name
        Track(name='foo').copy(name='bar')
        # Return an album with a new number of tracks
        Album(num_tracks=2).copy(num_tracks=5)

    :param values: the model fields to modify
    :type values: dict
    :rtype: new instance of the model being copied
    """
    # NOTE kwargs dict keys must be bytestrings to work on Python < 2.6.5
    # See https://github.com/mopidy/mopidy/issues/302 for details
    data = {}
    for key in self.__dict__.keys():
        public_key = key.lstrip("_")
        data[str(public_key)] = values.pop(public_key, self.__dict__[key])
    for key in values.keys():
        if hasattr(self, key):
            data[str(key)] = values.pop(key)
    if values:
        raise TypeError('copy() got an unexpected keyword argument "%s"' % key)
    return self.__class__(**data)


# Traceback (TypeError)
erik@faust:~$  mopidy
Traceback (most recent call last):
File "/usr/local/bin/mopidy", line 5, in <module>
main()
File "/usr/local/lib64/python2.6/site-packages/mopidy/__main__.py", line 48, in main
options = parse_options()
File "/usr/local/lib64/python2.6/site-packages/mopidy/__main__.py", line 85, in parse_options
help='show GStreamer help options')
File "/usr/lib64/python2.6/optparse.py", line 1012, in add_option
raise TypeError, "invalid arguments"
TypeError: invalid arguments
erik@faust:~$  python --version
Python 2.6
erik@faust:~$  uname -a
Linux faust 3.0.13-0.27-default #1 SMP Wed Feb 15 13:33:49 UTC 2012 (d73692b) x86_64 x86_64 x86_64 GNU/Linux
erik@faust:~$  cat /etc/SuSE-release
SUSE Linux Enterprise Server 11 (x86_64)
VERSION = 11
PATCHLEVEL = 2
erik@faust:~$

# Fixed code
def copy(self, **values):
    """
    Copy the model with ``field`` updated to new value.

    Examples::

        # Returns a track with a new name
        Track(name='foo').copy(name='bar')
        # Return an album with a new number of tracks
        Album(num_tracks=2).copy(num_tracks=5)

    :param values: the model fields to modify
    :type values: dict
    :rtype: new instance of the model being copied
    """
    data = {}
    for key in self.__dict__.keys():
        public_key = key.lstrip("_")
        data[public_key] = values.pop(public_key, self.__dict__[key])
    for key in values.keys():
        if hasattr(self, key):
            data[key] = values.pop(key)
    if values:
        raise TypeError('copy() got an unexpected keyword argument "%s"' % key)
    return self.__class__(**data)
# Buggy code
def model_json_decoder(dct):
    """
    Automatically deserialize Mopidy models from JSON.

    Usage::

        >>> import json
        >>> json.loads(
        ...     '{"a_track": {"__model__": "Track", "name": "name"}}',
        ...     object_hook=model_json_decoder)
        {u'a_track': Track(artists=[], name=u'name')}

    """
    # NOTE kwargs dict keys must be bytestrings to work on Python < 2.6.5
    # See https://github.com/mopidy/mopidy/issues/302 for details.
    if "__model__" in dct:
        model_name = dct.pop("__model__")
        cls = globals().get(model_name, None)
        if issubclass(cls, ImmutableObject):
            kwargs = {}
            for key, value in dct.items():
                kwargs[str(key)] = value
            return cls(**kwargs)
    return dct


# Traceback (TypeError)
erik@faust:~$  mopidy
Traceback (most recent call last):
File "/usr/local/bin/mopidy", line 5, in <module>
main()
File "/usr/local/lib64/python2.6/site-packages/mopidy/__main__.py", line 48, in main
options = parse_options()
File "/usr/local/lib64/python2.6/site-packages/mopidy/__main__.py", line 85, in parse_options
help='show GStreamer help options')
File "/usr/lib64/python2.6/optparse.py", line 1012, in add_option
raise TypeError, "invalid arguments"
TypeError: invalid arguments
erik@faust:~$  python --version
Python 2.6
erik@faust:~$  uname -a
Linux faust 3.0.13-0.27-default #1 SMP Wed Feb 15 13:33:49 UTC 2012 (d73692b) x86_64 x86_64 x86_64 GNU/Linux
erik@faust:~$  cat /etc/SuSE-release
SUSE Linux Enterprise Server 11 (x86_64)
VERSION = 11
PATCHLEVEL = 2
erik@faust:~$

# Fixed code
def model_json_decoder(dct):
    """
    Automatically deserialize Mopidy models from JSON.

    Usage::

        >>> import json
        >>> json.loads(
        ...     '{"a_track": {"__model__": "Track", "name": "name"}}',
        ...     object_hook=model_json_decoder)
        {u'a_track': Track(artists=[], name=u'name')}

    """
    if "__model__" in dct:
        model_name = dct.pop("__model__")
        cls = globals().get(model_name, None)
        if issubclass(cls, ImmutableObject):
            kwargs = {}
            for key, value in dct.items():
                kwargs[key] = value
            return cls(**kwargs)
    return dct
# Buggy code
def __init__(self, *args, **kwargs):
    # NOTE kwargs dict keys must be bytestrings to work on Python < 2.6.5
    # See https://github.com/mopidy/mopidy/issues/302 for details
    self.__dict__[b"artists"] = frozenset(kwargs.pop("artists", []))
    self.__dict__[b"images"] = frozenset(kwargs.pop("images", []))
    super(Album, self).__init__(*args, **kwargs)


# Traceback (TypeError)
erik@faust:~$  mopidy
Traceback (most recent call last):
File "/usr/local/bin/mopidy", line 5, in <module>
main()
File "/usr/local/lib64/python2.6/site-packages/mopidy/__main__.py", line 48, in main
options = parse_options()
File "/usr/local/lib64/python2.6/site-packages/mopidy/__main__.py", line 85, in parse_options
help='show GStreamer help options')
File "/usr/lib64/python2.6/optparse.py", line 1012, in add_option
raise TypeError, "invalid arguments"
TypeError: invalid arguments
erik@faust:~$  python --version
Python 2.6
erik@faust:~$  uname -a
Linux faust 3.0.13-0.27-default #1 SMP Wed Feb 15 13:33:49 UTC 2012 (d73692b) x86_64 x86_64 x86_64 GNU/Linux
erik@faust:~$  cat /etc/SuSE-release
SUSE Linux Enterprise Server 11 (x86_64)
VERSION = 11
PATCHLEVEL = 2
erik@faust:~$

# Fixed code
def __init__(self, *args, **kwargs):
    self.__dict__["artists"] = frozenset(kwargs.pop("artists", []))
    self.__dict__["images"] = frozenset(kwargs.pop("images", []))
    super(Album, self).__init__(*args, **kwargs)
# Buggy code
def __init__(self, *args, **kwargs):
    # NOTE kwargs dict keys must be bytestrings to work on Python < 2.6.5
    # See https://github.com/mopidy/mopidy/issues/302 for details
    self.__dict__[b"artists"] = frozenset(kwargs.pop("artists", []))
    super(Track, self).__init__(*args, **kwargs)


# Traceback (TypeError)
erik@faust:~$  mopidy
Traceback (most recent call last):
File "/usr/local/bin/mopidy", line 5, in <module>
main()
File "/usr/local/lib64/python2.6/site-packages/mopidy/__main__.py", line 48, in main
options = parse_options()
File "/usr/local/lib64/python2.6/site-packages/mopidy/__main__.py", line 85, in parse_options
help='show GStreamer help options')
File "/usr/lib64/python2.6/optparse.py", line 1012, in add_option
raise TypeError, "invalid arguments"
TypeError: invalid arguments
erik@faust:~$  python --version
Python 2.6
erik@faust:~$  uname -a
Linux faust 3.0.13-0.27-default #1 SMP Wed Feb 15 13:33:49 UTC 2012 (d73692b) x86_64 x86_64 x86_64 GNU/Linux
erik@faust:~$  cat /etc/SuSE-release
SUSE Linux Enterprise Server 11 (x86_64)
VERSION = 11
PATCHLEVEL = 2
erik@faust:~$

# Fixed code
def __init__(self, *args, **kwargs):
    self.__dict__["artists"] = frozenset(kwargs.pop("artists", []))
    super(Track, self).__init__(*args, **kwargs)
# Buggy code
def __init__(self, *args, **kwargs):
    # NOTE kwargs dict keys must be bytestrings to work on Python < 2.6.5
    # See https://github.com/mopidy/mopidy/issues/302 for details
    if len(args) == 2 and len(kwargs) == 0:
        kwargs[b"tlid"] = args[0]
        kwargs[b"track"] = args[1]
        args = []
    super(TlTrack, self).__init__(*args, **kwargs)


# Traceback (TypeError)
erik@faust:~$  mopidy
Traceback (most recent call last):
File "/usr/local/bin/mopidy", line 5, in <module>
main()
File "/usr/local/lib64/python2.6/site-packages/mopidy/__main__.py", line 48, in main
options = parse_options()
File "/usr/local/lib64/python2.6/site-packages/mopidy/__main__.py", line 85, in parse_options
help='show GStreamer help options')
File "/usr/lib64/python2.6/optparse.py", line 1012, in add_option
raise TypeError, "invalid arguments"
TypeError: invalid arguments
erik@faust:~$  python --version
Python 2.6
erik@faust:~$  uname -a
Linux faust 3.0.13-0.27-default #1 SMP Wed Feb 15 13:33:49 UTC 2012 (d73692b) x86_64 x86_64 x86_64 GNU/Linux
erik@faust:~$  cat /etc/SuSE-release
SUSE Linux Enterprise Server 11 (x86_64)
VERSION = 11
PATCHLEVEL = 2
erik@faust:~$

# Fixed code
def __init__(self, *args, **kwargs):
    if len(args) == 2 and len(kwargs) == 0:
        kwargs["tlid"] = args[0]
        kwargs["track"] = args[1]
        args = []
    super(TlTrack, self).__init__(*args, **kwargs)
# Buggy code
def __init__(self, *args, **kwargs):
    # NOTE kwargs dict keys must be bytestrings to work on Python < 2.6.5
    # See https://github.com/mopidy/mopidy/issues/302 for details
    self.__dict__[b"tracks"] = tuple(kwargs.pop("tracks", []))
    super(Playlist, self).__init__(*args, **kwargs)


# Traceback (TypeError)
erik@faust:~$  mopidy
Traceback (most recent call last):
File "/usr/local/bin/mopidy", line 5, in <module>
main()
File "/usr/local/lib64/python2.6/site-packages/mopidy/__main__.py", line 48, in main
options = parse_options()
File "/usr/local/lib64/python2.6/site-packages/mopidy/__main__.py", line 85, in parse_options
help='show GStreamer help options')
File "/usr/lib64/python2.6/optparse.py", line 1012, in add_option
raise TypeError, "invalid arguments"
TypeError: invalid arguments
erik@faust:~$  python --version
Python 2.6
erik@faust:~$  uname -a
Linux faust 3.0.13-0.27-default #1 SMP Wed Feb 15 13:33:49 UTC 2012 (d73692b) x86_64 x86_64 x86_64 GNU/Linux
erik@faust:~$  cat /etc/SuSE-release
SUSE Linux Enterprise Server 11 (x86_64)
VERSION = 11
PATCHLEVEL = 2
erik@faust:~$

# Fixed code
def __init__(self, *args, **kwargs):
    self.__dict__["tracks"] = tuple(kwargs.pop("tracks", []))
    super(Playlist, self).__init__(*args, **kwargs)
# Buggy code
def __init__(self, *args, **kwargs):
    # NOTE kwargs dict keys must be bytestrings to work on Python < 2.6.5
    # See https://github.com/mopidy/mopidy/issues/302 for details
    self.__dict__[b"tracks"] = tuple(kwargs.pop("tracks", []))
    self.__dict__[b"artists"] = tuple(kwargs.pop("artists", []))
    self.__dict__[b"albums"] = tuple(kwargs.pop("albums", []))
    super(SearchResult, self).__init__(*args, **kwargs)


# Traceback (TypeError)
erik@faust:~$  mopidy
Traceback (most recent call last):
File "/usr/local/bin/mopidy", line 5, in <module>
main()
File "/usr/local/lib64/python2.6/site-packages/mopidy/__main__.py", line 48, in main
options = parse_options()
File "/usr/local/lib64/python2.6/site-packages/mopidy/__main__.py", line 85, in parse_options
help='show GStreamer help options')
File "/usr/lib64/python2.6/optparse.py", line 1012, in add_option
raise TypeError, "invalid arguments"
TypeError: invalid arguments
erik@faust:~$  python --version
Python 2.6
erik@faust:~$  uname -a
Linux faust 3.0.13-0.27-default #1 SMP Wed Feb 15 13:33:49 UTC 2012 (d73692b) x86_64 x86_64 x86_64 GNU/Linux
erik@faust:~$  cat /etc/SuSE-release
SUSE Linux Enterprise Server 11 (x86_64)
VERSION = 11
PATCHLEVEL = 2
erik@faust:~$

# Fixed code
def __init__(self, *args, **kwargs):
    self.__dict__["tracks"] = tuple(kwargs.pop("tracks", []))
    self.__dict__["artists"] = tuple(kwargs.pop("artists", []))
    self.__dict__["albums"] = tuple(kwargs.pop("albums", []))
    super(SearchResult, self).__init__(*args, **kwargs)
# Buggy code
def parse_options():
    parser = optparse.OptionParser(version="Mopidy %s" % versioning.get_version())
    # NOTE First argument to add_option must be bytestrings on Python < 2.6.2
    # See https://github.com/mopidy/mopidy/issues/302 for details
    parser.add_option(
        b"-q",
        "--quiet",
        action="store_const",
        const=0,
        dest="verbosity_level",
        help="less output (warning level)",
    )
    parser.add_option(
        b"-v",
        "--verbose",
        action="count",
        default=1,
        dest="verbosity_level",
        help="more output (debug level)",
    )
    return parser.parse_args(args=mopidy_args)[0]


# Traceback (TypeError)
erik@faust:~$  mopidy
Traceback (most recent call last):
File "/usr/local/bin/mopidy", line 5, in <module>
main()
File "/usr/local/lib64/python2.6/site-packages/mopidy/__main__.py", line 48, in main
options = parse_options()
File "/usr/local/lib64/python2.6/site-packages/mopidy/__main__.py", line 85, in parse_options
help='show GStreamer help options')
File "/usr/lib64/python2.6/optparse.py", line 1012, in add_option
raise TypeError, "invalid arguments"
TypeError: invalid arguments
erik@faust:~$  python --version
Python 2.6
erik@faust:~$  uname -a
Linux faust 3.0.13-0.27-default #1 SMP Wed Feb 15 13:33:49 UTC 2012 (d73692b) x86_64 x86_64 x86_64 GNU/Linux
erik@faust:~$  cat /etc/SuSE-release
SUSE Linux Enterprise Server 11 (x86_64)
VERSION = 11
PATCHLEVEL = 2
erik@faust:~$

# Fixed code
def parse_options():
    parser = optparse.OptionParser(version="Mopidy %s" % versioning.get_version())
    parser.add_option(
        "-q",
        "--quiet",
        action="store_const",
        const=0,
        dest="verbosity_level",
        help="less output (warning level)",
    )
    parser.add_option(
        "-v",
        "--verbose",
        action="count",
        default=1,
        dest="verbosity_level",
        help="more output (debug level)",
    )
    return parser.parse_args(args=mopidy_args)[0]
# Buggy code
def _retrieve(source_key, target_key, target):
    if source_key in data:
        target[str(target_key)] = data[source_key]


# Traceback (TypeError)
erik@faust:~$  mopidy
Traceback (most recent call last):
File "/usr/local/bin/mopidy", line 5, in <module>
main()
File "/usr/local/lib64/python2.6/site-packages/mopidy/__main__.py", line 48, in main
options = parse_options()
File "/usr/local/lib64/python2.6/site-packages/mopidy/__main__.py", line 85, in parse_options
help='show GStreamer help options')
File "/usr/lib64/python2.6/optparse.py", line 1012, in add_option
raise TypeError, "invalid arguments"
TypeError: invalid arguments
erik@faust:~$  python --version
Python 2.6
erik@faust:~$  uname -a
Linux faust 3.0.13-0.27-default #1 SMP Wed Feb 15 13:33:49 UTC 2012 (d73692b) x86_64 x86_64 x86_64 GNU/Linux
erik@faust:~$  cat /etc/SuSE-release
SUSE Linux Enterprise Server 11 (x86_64)
VERSION = 11
PATCHLEVEL = 2
erik@faust:~$

# Fixed code
def _retrieve(source_key, target_key, target):
    if source_key in data:
        target[target_key] = data[source_key]
# Buggy code
def parse_m3u(file_path):
    """
    Convert M3U file list of uris

    Example M3U data::

        # This is a comment
        Alternative\Band - Song.mp3
        Classical\Other Band - New Song.mp3
        Stuff.mp3
        D:\More Music\Foo.mp3
        http://www.example.com:8000/Listen.pls
        http://www.example.com/~user/Mine.mp3

    - Relative paths of songs should be with respect to location of M3U.
    - Paths are normaly platform specific.
    - Lines starting with # should be ignored.
    - m3u files are latin-1.
    - This function does not bother with Extended M3U directives.
    """

    uris = []
    folder = os.path.dirname(file_path)

    try:
        with open(file_path) as m3u:
            contents = m3u.readlines()
    except IOError as error:
        logger.error("Couldn't open m3u: %s", locale_decode(error))
        return uris

    for line in contents:
        line = line.strip().decode("latin1")

        if line.startswith("#"):
            continue

        # FIXME what about other URI types?
        if line.startswith("file://"):
            uris.append(line)
        else:
            path = path_to_uri(folder, line)
            uris.append(path)

    return uris


# Traceback (TypeError)
$ PYTHONPATH=. ./bin/mopidy-scan
INFO     2012-09-11 15:56:32,431 [15354:MainThread] root
Scanning None
Traceback (most recent call last):
File "./bin/mopidy-scan", line 26, in <module>
scanner = Scanner(settings.LOCAL_MUSIC_PATH, store, debug)
File "/home/jodal/dev/mopidy/mopidy/scanner.py", line 55, in __init__
self.uris = [path_to_uri(f) for f in find_files(folder)]
File "/home/jodal/dev/mopidy/mopidy/utils/path.py", line 53, in find_files
if os.path.isfile(path):
File "/home/jodal/dev/virtualenvs/mopidy/lib/python2.7/genericpath.py", line 29, in isfile
st = os.stat(path)
TypeError: coercing to Unicode: need string or buffer, NoneType found

# Fixed code
def parse_m3u(file_path, music_folder):
    """
    Convert M3U file list of uris

    Example M3U data::

        # This is a comment
        Alternative\Band - Song.mp3
        Classical\Other Band - New Song.mp3
        Stuff.mp3
        D:\More Music\Foo.mp3
        http://www.example.com:8000/Listen.pls
        http://www.example.com/~user/Mine.mp3

    - Relative paths of songs should be with respect to location of M3U.
    - Paths are normaly platform specific.
    - Lines starting with # should be ignored.
    - m3u files are latin-1.
    - This function does not bother with Extended M3U directives.
    """

    uris = []
    try:
        with open(file_path) as m3u:
            contents = m3u.readlines()
    except IOError as error:
        logger.error("Couldn't open m3u: %s", locale_decode(error))
        return uris

    for line in contents:
        line = line.strip().decode("latin1")

        if line.startswith("#"):
            continue

        # FIXME what about other URI types?
        if line.startswith("file://"):
            uris.append(line)
        else:
            path = path_to_uri(music_folder, line)
            uris.append(path)

    return uris
# Buggy code
def __init__(self, folder, data_callback, error_callback=None):
    self.uris = [path_to_uri(f) for f in find_files(folder)]
    self.data_callback = data_callback
    self.error_callback = error_callback
    self.loop = gobject.MainLoop()

    fakesink = gst.element_factory_make("fakesink")

    self.uribin = gst.element_factory_make("uridecodebin")
    self.uribin.set_property("caps", gst.Caps("audio/x-raw-int"))
    self.uribin.connect("pad-added", self.process_new_pad, fakesink.get_pad("sink"))

    self.pipe = gst.element_factory_make("pipeline")
    self.pipe.add(self.uribin)
    self.pipe.add(fakesink)

    bus = self.pipe.get_bus()
    bus.add_signal_watch()
    bus.connect("message::tag", self.process_tags)
    bus.connect("message::error", self.process_error)


# Traceback (TypeError)
$ PYTHONPATH=. ./bin/mopidy-scan
INFO     2012-09-11 15:56:32,431 [15354:MainThread] root
Scanning None
Traceback (most recent call last):
File "./bin/mopidy-scan", line 26, in <module>
scanner = Scanner(settings.LOCAL_MUSIC_PATH, store, debug)
File "/home/jodal/dev/mopidy/mopidy/scanner.py", line 55, in __init__
self.uris = [path_to_uri(f) for f in find_files(folder)]
File "/home/jodal/dev/mopidy/mopidy/utils/path.py", line 53, in find_files
if os.path.isfile(path):
File "/home/jodal/dev/virtualenvs/mopidy/lib/python2.7/genericpath.py", line 29, in isfile
st = os.stat(path)
TypeError: coercing to Unicode: need string or buffer, NoneType found

# Fixed code
def __init__(self, folder, data_callback, error_callback=None):
    self.files = find_files(folder)
    self.data_callback = data_callback
    self.error_callback = error_callback
    self.loop = gobject.MainLoop()

    fakesink = gst.element_factory_make("fakesink")

    self.uribin = gst.element_factory_make("uridecodebin")
    self.uribin.set_property("caps", gst.Caps("audio/x-raw-int"))
    self.uribin.connect("pad-added", self.process_new_pad, fakesink.get_pad("sink"))

    self.pipe = gst.element_factory_make("pipeline")
    self.pipe.add(self.uribin)
    self.pipe.add(fakesink)

    bus = self.pipe.get_bus()
    bus.add_signal_watch()
    bus.connect("message::tag", self.process_tags)
    bus.connect("message::error", self.process_error)
# Buggy code
def next_uri(self):
    if not self.uris:
        return self.stop()

    self.pipe.set_state(gst.STATE_NULL)
    self.uribin.set_property("uri", self.uris.pop())
    self.pipe.set_state(gst.STATE_PAUSED)


# Traceback (TypeError)
$ PYTHONPATH=. ./bin/mopidy-scan
INFO     2012-09-11 15:56:32,431 [15354:MainThread] root
Scanning None
Traceback (most recent call last):
File "./bin/mopidy-scan", line 26, in <module>
scanner = Scanner(settings.LOCAL_MUSIC_PATH, store, debug)
File "/home/jodal/dev/mopidy/mopidy/scanner.py", line 55, in __init__
self.uris = [path_to_uri(f) for f in find_files(folder)]
File "/home/jodal/dev/mopidy/mopidy/utils/path.py", line 53, in find_files
if os.path.isfile(path):
File "/home/jodal/dev/virtualenvs/mopidy/lib/python2.7/genericpath.py", line 29, in isfile
st = os.stat(path)
TypeError: coercing to Unicode: need string or buffer, NoneType found

# Fixed code
def next_uri(self):
    try:
        uri = path_to_uri(self.files.next())
    except StopIteration:
        self.stop()
        return False
    self.pipe.set_state(gst.STATE_NULL)
    self.uribin.set_property("uri", uri)
    self.pipe.set_state(gst.STATE_PAUSED)
    return True
# Buggy code
def start(self):
    if not self.uris:
        return
    self.next_uri()
    self.loop.run()


# Traceback (TypeError)
$ PYTHONPATH=. ./bin/mopidy-scan
INFO     2012-09-11 15:56:32,431 [15354:MainThread] root
Scanning None
Traceback (most recent call last):
File "./bin/mopidy-scan", line 26, in <module>
scanner = Scanner(settings.LOCAL_MUSIC_PATH, store, debug)
File "/home/jodal/dev/mopidy/mopidy/scanner.py", line 55, in __init__
self.uris = [path_to_uri(f) for f in find_files(folder)]
File "/home/jodal/dev/mopidy/mopidy/utils/path.py", line 53, in find_files
if os.path.isfile(path):
File "/home/jodal/dev/virtualenvs/mopidy/lib/python2.7/genericpath.py", line 29, in isfile
st = os.stat(path)
TypeError: coercing to Unicode: need string or buffer, NoneType found

# Fixed code
def start(self):
    if self.next_uri():
        self.loop.run()
# Buggy code
def __init__(self, key_prefixes):
    key_prefixes = map(self._sanitize, key_prefixes)
    # compute read and write dirs from base runtime dirs: the first base
    # dir is selected for writes and prefered for reads
    self._read_dirs = [os.path.join(x, *key_prefixes) for x in get_runtime_dirs()]
    self._write_dir = self._read_dirs[0]
    os.makedirs(self._write_dir, exist_ok=True)
    if sys.platform == "linux":
        # set the sticky bit to prevent removal during cleanup
        os.chmod(self._write_dir, 0o1700)
    _LOGGER.debug("data in %s", self._write_dir)


# Traceback (ValueError)
C:\>liquidctl list --verbose
Device ID 0: Corsair H100i PRO XT (experimental)
├── Vendor ID: 0x1b1c
├── Product ID: 0x0c20
├── Release number: 0x0100
├── Bus: hid
├── Address: \\?\hid#vid_1b1c&amp;pid_0c20#7&amp;1e4e78f5&amp;0&amp;0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
└── Driver: HydroPlatinum using module hid


C:\>liquidctl initialize all
ERROR: Unexpected error with Corsair H100i PRO XT (experimental)
Traceback (most recent call last):
ValueError: source code string cannot contain null bytes

# Fixed code
def __init__(self, key_prefixes, runtime_dirs=get_runtime_dirs()):
    key_prefixes = map(self._sanitize, key_prefixes)
    # compute read and write dirs from base runtime dirs: the first base
    # dir is selected for writes and prefered for reads
    self._read_dirs = [os.path.join(x, *key_prefixes) for x in runtime_dirs]
    self._write_dir = self._read_dirs[0]
    os.makedirs(self._write_dir, exist_ok=True)
    if sys.platform == "linux":
        # set the sticky bit to prevent removal during cleanup
        os.chmod(self._write_dir, 0o1700)
    _LOGGER.debug("data in %s", self._write_dir)
# Buggy code
def load(self, key):
    for base in self._read_dirs:
        path = os.path.join(base, key)
        if not os.path.isfile(path):
            continue
        try:
            with open(path, mode="r") as f:
                data = f.read().strip()
                if len(data) == 0:
                    value = None
                else:
                    value = literal_eval(data)
                _LOGGER.debug("loaded %s=%r (from %s)", key, value, path)
        except OSError as err:
            _LOGGER.warning("%s exists but cannot be read: %s", path, err)
            continue
        return value
    _LOGGER.debug("no data (file) found for %s", key)
    return None


# Traceback (ValueError)
C:\>liquidctl list --verbose
Device ID 0: Corsair H100i PRO XT (experimental)
├── Vendor ID: 0x1b1c
├── Product ID: 0x0c20
├── Release number: 0x0100
├── Bus: hid
├── Address: \\?\hid#vid_1b1c&amp;pid_0c20#7&amp;1e4e78f5&amp;0&amp;0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
└── Driver: HydroPlatinum using module hid


C:\>liquidctl initialize all
ERROR: Unexpected error with Corsair H100i PRO XT (experimental)
Traceback (most recent call last):
ValueError: source code string cannot contain null bytes

# Fixed code
def load(self, key):
    for base in self._read_dirs:
        path = os.path.join(base, key)
        if not os.path.isfile(path):
            continue
        try:
            with open(path, mode="r") as f:
                data = f.read().strip()
                if len(data) == 0:
                    value = None
                else:
                    value = literal_eval(data)
                _LOGGER.debug("loaded %s=%r (from %s)", key, value, path)
        except OSError as err:
            _LOGGER.warning("%s exists but could not be read: %s", path, err)
        except ValueError as err:
            _LOGGER.warning("%s exists but was corrupted: %s", key, err)
        else:
            return value

    _LOGGER.debug("no data (file) found for %s", key)
    return None
# Buggy code
def _write(self, data):
    padding = [0x0] * (_WRITE_LENGTH - len(data))
    self.device.write(data + padding)


# Traceback (AssertionError)
PS E:\liquidctl> .\liquidctl status
NZXT Kraken X (X42, X52, X62 or X72)
├── Liquid temperature     30.4  °C
├── Fan speed              1100  rpm
├── Pump speed             2703  rpm
└── Firmware version      6.0.2

ERROR: Unexpected error with NZXT E850 (experimental)
Traceback (most recent call last):
AssertionError: invalid response (attempts=3)

And here is the debug output:

[DEBUG] __main__: device: NZXT E850 (experimental)
[DEBUG] liquidctl.driver.usb: discarded 0 previously enqueued reports
[DEBUG] liquidctl.driver.usb: writting report 0xad with 63 bytes: 00:03:01:60:fc:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
[DEBUG] liquidctl.driver.usb: read 64 bytes: aa:04:02:08:d2:45:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
[DEBUG] liquidctl.driver.usb: writting report 0xad with 63 bytes: 00:03:01:60:fc:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
[DEBUG] liquidctl.driver.usb: read 64 bytes: aa:04:02:08:d2:45:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
[DEBUG] liquidctl.driver.usb: writting report 0xad with 63 bytes: 00:03:01:60:fc:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
[DEBUG] liquidctl.driver.usb: read 64 bytes: aa:04:02:08:d2:45:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
[ERROR] __main__: Unexpected error with NZXT E850 (experimental)
Traceback (most recent call last):
File "liquidctl\cli.py", line 302, in main
File "liquidctl\driver\nzxt_epsu.py", line 59, in get_status
File "liquidctl\driver\nzxt_epsu.py", line 145, in _get_fw_versions
File "liquidctl\driver\nzxt_epsu.py", line 113, in _exec_read
AssertionError: invalid response (attempts=3)

# Fixed code
def _write(self, data):
    assert len(data) <= _REPORT_LENGTH
    packet = bytearray(1 + _REPORT_LENGTH)
    packet[1 : 1 + len(data)] = data  # device doesn't use numbered reports
    self.device.write(packet)
# Buggy code
def _read(self):
    return self.device.read(_READ_LENGTH)


# Traceback (AssertionError)
PS E:\liquidctl> .\liquidctl status
NZXT Kraken X (X42, X52, X62 or X72)
├── Liquid temperature     30.4  °C
├── Fan speed              1100  rpm
├── Pump speed             2703  rpm
└── Firmware version      6.0.2

ERROR: Unexpected error with NZXT E850 (experimental)
Traceback (most recent call last):
AssertionError: invalid response (attempts=3)

And here is the debug output:

[DEBUG] __main__: device: NZXT E850 (experimental)
[DEBUG] liquidctl.driver.usb: discarded 0 previously enqueued reports
[DEBUG] liquidctl.driver.usb: writting report 0xad with 63 bytes: 00:03:01:60:fc:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
[DEBUG] liquidctl.driver.usb: read 64 bytes: aa:04:02:08:d2:45:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
[DEBUG] liquidctl.driver.usb: writting report 0xad with 63 bytes: 00:03:01:60:fc:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
[DEBUG] liquidctl.driver.usb: read 64 bytes: aa:04:02:08:d2:45:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
[DEBUG] liquidctl.driver.usb: writting report 0xad with 63 bytes: 00:03:01:60:fc:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
[DEBUG] liquidctl.driver.usb: read 64 bytes: aa:04:02:08:d2:45:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
[ERROR] __main__: Unexpected error with NZXT E850 (experimental)
Traceback (most recent call last):
File "liquidctl\cli.py", line 302, in main
File "liquidctl\driver\nzxt_epsu.py", line 59, in get_status
File "liquidctl\driver\nzxt_epsu.py", line 145, in _get_fw_versions
File "liquidctl\driver\nzxt_epsu.py", line 113, in _exec_read
AssertionError: invalid response (attempts=3)

# Fixed code
def _read(self):
    return self.device.read(_REPORT_LENGTH)
# Buggy code
def connect(self, **kwargs):
    """Connect to the device."""
    super().connect(**kwargs)
    ids = f"vid{self.vendor_id:04x}_pid{self.product_id:04x}"
    # must use the HID path because there is no serial number; however,
    # these can be quite long on Windows and macOS, so only take the
    # numbers, since they are likely the only parts that vary between two
    # devices of the same model
    loc = "loc" + "_".join((num.decode() for num in re.findall(b"\\d+", self.address)))
    self._data = RuntimeStorage(key_prefixes=[ids, loc])
    self._sequence = _sequence(self._data)


# Traceback (TypeError)
[DEBUG] __main__: device: Corsair H115i PRO XT (experimental)
self.address: "/dev/hidraw1"
Traceback (most recent call last):
File "/usr/lib/python3.8/runpy.py", line 194, in _run_module_as_main
return _run_code(code, main_globals, None,
File "/usr/lib/python3.8/runpy.py", line 87, in _run_code
exec(code, run_globals)
File "/home/meta/src/liquidctl/liquidctl/cli.py", line 327, in <module>
main()
File "/home/meta/src/liquidctl/liquidctl/cli.py", line 297, in main
dev.connect(**opts)
File "/home/meta/src/liquidctl/liquidctl/driver/hydro_platinum.py", line 158, in connect
loc = 'loc' + '_'.join((num.decode() for num in re.findall(b'\\d+', self.address)))
File "/usr/lib/python3.8/re.py", line 241, in findall
return _compile(pattern, flags).findall(string)
TypeError: cannot use a bytes pattern on a string-like object

# Fixed code
def connect(self, **kwargs):
    """Connect to the device."""
    super().connect(**kwargs)
    ids = f"vid{self.vendor_id:04x}_pid{self.product_id:04x}"
    # must use the HID path because there is no serial number; however,
    # these can be quite long on Windows and macOS, so only take the
    # numbers, since they are likely the only parts that vary between two
    # devices of the same model
    loc = "loc" + "_".join(re.findall(r"\d+", self.address))
    self._data = RuntimeStorage(key_prefixes=[ids, loc])
    self._sequence = _sequence(self._data)
# Buggy code
def connect(self, **kwargs):
    """Connect to the device."""
    super().connect()
    try:
        self._open()
    except usb.core.USBError as err:
        LOGGER.warning("report: failed to open right away, will close first")
        LOGGER.debug(err, exc_info=True)
        self._close()
        self._open()
    finally:
        self.device.release()


# Traceback (usb.core.USBError)
# extra/liquiddump --product 0xb200 --interval 3
{"Asetek 690LC (assuming EVGA CLC)": [["Liquid temperature", 28.8, "\u00b0C"], ["Fan speed", 420, "rpm"], ["Pump speed", 2670, "rpm"], ["Firmware version", "2.10.0.0", ""]]}
{"Asetek 690LC (assuming EVGA CLC)": [["Liquid temperature", 28.8, "\u00b0C"], ["Fan speed", 480, "rpm"], ["Pump speed", 2610, "rpm"], ["Firmware version", "2.10.0.0", ""]]}
{"Asetek 690LC (assuming EVGA CLC)": [["Liquid temperature", 28.8, "\u00b0C"], ["Fan speed", 420, "rpm"], ["Pump speed", 2640, "rpm"], ["Firmware version", "2.10.0.0", ""]]}
Unexpected error
Traceback (most recent call last):
File "extra/liquiddump", line 92, in <module>
status[d.description] = d.get_status()
File "/usr/lib/python3.7/site-packages/liquidctl/driver/asetek.py", line 221, in get_status
msg = self._end_transaction_and_read()
File "/usr/lib/python3.7/site-packages/liquidctl/driver/asetek.py", line 140, in _end_transaction_and_read
msg = self.device.read(_READ_ENDPOINT, _READ_LENGTH, _READ_TIMEOUT)
File "/usr/lib/python3.7/site-packages/liquidctl/driver/usb.py", line 260, in read
return self.usbdev.read(endpoint, length, timeout=timeout)
File "/usr/lib/python3.7/site-packages/usb/core.py", line 988, in read
self.__get_timeout(timeout))
File "/usr/lib/python3.7/site-packages/usb/backend/libusb1.py", line 833, in bulk_read
timeout)
File "/usr/lib/python3.7/site-packages/usb/backend/libusb1.py", line 936, in __read
_check(retval)
File "/usr/lib/python3.7/site-packages/usb/backend/libusb1.py", line 595, in _check
raise USBError(_strerror(ret), ret, _libusb_errno[ret])
usb.core.USBError: [Errno 110] Operation timed out

$ echo $?
0

# Fixed code
def connect(self, **kwargs):
    """Connect to the device.

    Enables the device to send data to the host."""
    super().connect(**kwargs)
    self._configure_flow_control(clear_to_send=True)
# Buggy code
def disconnect(self, **kwargs):
    """Disconnect from the device."""
    self._close()
    super().disconnect()
    self.device.release()


# Traceback (usb.core.USBError)
# extra/liquiddump --product 0xb200 --interval 3
{"Asetek 690LC (assuming EVGA CLC)": [["Liquid temperature", 28.8, "\u00b0C"], ["Fan speed", 420, "rpm"], ["Pump speed", 2670, "rpm"], ["Firmware version", "2.10.0.0", ""]]}
{"Asetek 690LC (assuming EVGA CLC)": [["Liquid temperature", 28.8, "\u00b0C"], ["Fan speed", 480, "rpm"], ["Pump speed", 2610, "rpm"], ["Firmware version", "2.10.0.0", ""]]}
{"Asetek 690LC (assuming EVGA CLC)": [["Liquid temperature", 28.8, "\u00b0C"], ["Fan speed", 420, "rpm"], ["Pump speed", 2640, "rpm"], ["Firmware version", "2.10.0.0", ""]]}
Unexpected error
Traceback (most recent call last):
File "extra/liquiddump", line 92, in <module>
status[d.description] = d.get_status()
File "/usr/lib/python3.7/site-packages/liquidctl/driver/asetek.py", line 221, in get_status
msg = self._end_transaction_and_read()
File "/usr/lib/python3.7/site-packages/liquidctl/driver/asetek.py", line 140, in _end_transaction_and_read
msg = self.device.read(_READ_ENDPOINT, _READ_LENGTH, _READ_TIMEOUT)
File "/usr/lib/python3.7/site-packages/liquidctl/driver/usb.py", line 260, in read
return self.usbdev.read(endpoint, length, timeout=timeout)
File "/usr/lib/python3.7/site-packages/usb/core.py", line 988, in read
self.__get_timeout(timeout))
File "/usr/lib/python3.7/site-packages/usb/backend/libusb1.py", line 833, in bulk_read
timeout)
File "/usr/lib/python3.7/site-packages/usb/backend/libusb1.py", line 936, in __read
_check(retval)
File "/usr/lib/python3.7/site-packages/usb/backend/libusb1.py", line 595, in _check
raise USBError(_strerror(ret), ret, _libusb_errno[ret])
usb.core.USBError: [Errno 110] Operation timed out

$ echo $?
0

# Fixed code
def disconnect(self, **kwargs):
    """Disconnect from the device.

    Implementation note: unlike SI_Close is supposed to do,¹ do not send
    _USBXPRESS_NOT_CLEAR_TO_SEND to the device.  This allows one program to
    disconnect without sotping reads from another.

    Surrounding device.read() with _USBXPRESS_[NOT_]CLEAR_TO_SEND would
    make more sense, but there seems to be a yet unknown minimum delay
    necessary for that to work well.

    ¹ https://github.com/craigshelley/SiUSBXp/blob/master/SiUSBXp.c
    """
    super().disconnect(**kwargs)