From 81f388fe4ab7fe591d68cc3f14753247eaa4992d Mon Sep 17 00:00:00 2001 From: Philipp Wolfer Date: Mon, 19 Jan 2026 11:40:42 +0100 Subject: [PATCH 1/3] Reformat all code with ruff format --- discid/__init__.py | 8 +- discid/disc.py | 94 +++++++++++------------ discid/libdiscid.py | 49 +++++++----- discid/track.py | 15 ++-- discid/util.py | 20 ++--- doc/conf.py | 90 +++++++++++++--------- examples.py | 20 +++-- pyproject.toml | 1 - test_discid.py | 177 ++++++++++++++++++++++++++------------------ 9 files changed, 273 insertions(+), 201 deletions(-) diff --git a/discid/__init__.py b/discid/__init__.py index 32fa0d7..3e724cb 100644 --- a/discid/__init__.py +++ b/discid/__init__.py @@ -27,11 +27,11 @@ and will raise :exc:`OSError` when libdiscid is not found. """ -from discid.disc import read, put, Disc, DiscError, TOCError -from discid.track import Track -from discid.libdiscid import get_default_device -import discid.libdiscid import discid.disc +import discid.libdiscid +from discid.disc import Disc, DiscError, TOCError, put, read +from discid.libdiscid import get_default_device +from discid.track import Track __version__ = "1.3.0" diff --git a/discid/disc.py b/discid/disc.py index 5200d56..dd007c6 100644 --- a/discid/disc.py +++ b/discid/disc.py @@ -15,16 +15,14 @@ # # Please submit bug reports to GitHub: # https://github.com/metabrainz/python-discid/issues -"""Disc class -""" +"""Disc class""" import re -from ctypes import c_int, c_void_p, c_char_p, c_uint +from ctypes import c_char_p, c_int, c_uint, c_void_p from discid.libdiscid import _LIB, FEATURES -from discid.util import _encode, _decode, _sectors_to_seconds from discid.track import Track - +from discid.util import _decode, _encode, _sectors_to_seconds # our implementation of libdiscid's enum discid_feature _FEATURE_MAPPING = {"read": 1 << 0, "mcn": 1 << 1, "isrc": 1 << 2} @@ -32,6 +30,7 @@ FEATURES_IMPLEMENTED = list(_FEATURE_MAPPING.keys()) + def read(device=None, features=None): """Reads the TOC from the device given as string and returns a :class:`Disc` object. @@ -54,6 +53,7 @@ def read(device=None, features=None): disc.read(device, features) return disc + def put(first, last, disc_sectors, track_offsets): """Creates a TOC based on the information given and returns a :class:`Disc` object. @@ -77,23 +77,25 @@ def put(first, last, disc_sectors, track_offsets): class DiscError(IOError): - """:func:`read` will raise this exception when an error occurred. - """ + """:func:`read` will raise this exception when an error occurred.""" + pass + class TOCError(Exception): """:func:`put` will raise this exception when illegal parameters are provided. """ + pass class Disc(object): - """The class of the object returned by :func:`read` or :func:`put`. - """ + """The class of the object returned by :func:`read` or :func:`put`.""" _LIB.discid_new.argtypes = () _LIB.discid_new.restype = c_void_p + def __init__(self): """The initialization will reserve some memory for internal data structures. @@ -107,15 +109,14 @@ def __str__(self): assert self._success return self.id - _LIB.discid_get_error_msg.argtypes = (c_void_p, ) + _LIB.discid_get_error_msg.argtypes = (c_void_p,) _LIB.discid_get_error_msg.restype = c_char_p + def _get_error_msg(self): - """Get the error message for the last error with the object. - """ + """Get the error message for the last error with the object.""" error = _LIB.discid_get_error_msg(self._handle) return _decode(error) - _LIB.discid_read.argtypes = (c_void_p, c_char_p) _LIB.discid_read.restype = c_int try: @@ -123,6 +124,7 @@ def _get_error_msg(self): _LIB.discid_read_sparse.restype = c_int except AttributeError: pass + def read(self, device=None, features=None): """Reads the TOC from the device given as string @@ -135,8 +137,9 @@ def read(self, device=None, features=None): features = [] # only use features implemented on this platform and in this module - self._requested_features = list(set(features) & set(FEATURES) - & set(FEATURES_IMPLEMENTED)) + self._requested_features = list( + set(features) & set(FEATURES) & set(FEATURES_IMPLEMENTED) + ) # create the bitmask for libdiscid c_features = 0 @@ -145,8 +148,9 @@ def read(self, device=None, features=None): # device = None will use the default device (internally) try: - result = _LIB.discid_read_sparse(self._handle, _encode(device), - c_features) == 1 + result = ( + _LIB.discid_read_sparse(self._handle, _encode(device), c_features) == 1 + ) except AttributeError: result = _LIB.discid_read(self._handle, _encode(device)) == 1 self._success = result @@ -156,6 +160,7 @@ def read(self, device=None, features=None): _LIB.discid_put.argtypes = (c_void_p, c_int, c_int, c_void_p) _LIB.discid_put.restype = c_int + def put(self, first, last, disc_sectors, track_offsets): """Creates a TOC based on the input given. @@ -185,27 +190,27 @@ def put(self, first, last, disc_sectors, track_offsets): raise TOCError(self._get_error_msg()) return self._success - - _LIB.discid_get_id.argtypes = (c_void_p, ) + _LIB.discid_get_id.argtypes = (c_void_p,) _LIB.discid_get_id.restype = c_char_p + def _get_id(self): - """Gets the current MusicBrainz disc ID - """ + """Gets the current MusicBrainz disc ID""" assert self._success result = _LIB.discid_get_id(self._handle) return _decode(result) - _LIB.discid_get_freedb_id.argtypes = (c_void_p, ) + _LIB.discid_get_freedb_id.argtypes = (c_void_p,) _LIB.discid_get_freedb_id.restype = c_char_p + def _get_freedb_id(self): - """Gets the current FreeDB disc ID - """ + """Gets the current FreeDB disc ID""" assert self._success result = _LIB.discid_get_freedb_id(self._handle) return _decode(result) - _LIB.discid_get_submission_url.argtypes = (c_void_p, ) + _LIB.discid_get_submission_url.argtypes = (c_void_p,) _LIB.discid_get_submission_url.restype = c_char_p + def _get_submission_url(self): """Give an URL to submit the current TOC as a new Disc ID to MusicBrainz. @@ -215,10 +220,11 @@ def _get_submission_url(self): return _decode(result) try: - _LIB.discid_get_toc_string.argtypes = (c_void_p, ) + _LIB.discid_get_toc_string.argtypes = (c_void_p,) _LIB.discid_get_toc_string.restype = c_char_p except AttributeError: pass + def _get_toc_string(self): """The TOC suitable as value of the `toc parameter` when accessing the MusicBrainz Web Service. @@ -231,38 +237,38 @@ def _get_toc_string(self): else: return _decode(result) - _LIB.discid_get_first_track_num.argtypes = (c_void_p, ) + _LIB.discid_get_first_track_num.argtypes = (c_void_p,) _LIB.discid_get_first_track_num.restype = c_int + def _get_first_track_num(self): - """Gets the first track number - """ + """Gets the first track number""" assert self._success return _LIB.discid_get_first_track_num(self._handle) - _LIB.discid_get_last_track_num.argtypes = (c_void_p, ) + _LIB.discid_get_last_track_num.argtypes = (c_void_p,) _LIB.discid_get_last_track_num.restype = c_int + def _get_last_track_num(self): - """Gets the last track number - """ + """Gets the last track number""" assert self._success return _LIB.discid_get_last_track_num(self._handle) - _LIB.discid_get_sectors.argtypes = (c_void_p, ) + _LIB.discid_get_sectors.argtypes = (c_void_p,) _LIB.discid_get_sectors.restype = c_int + def _get_sectors(self): - """Gets the total number of sectors on the disc - """ + """Gets the total number of sectors on the disc""" assert self._success return _LIB.discid_get_sectors(self._handle) try: - _LIB.discid_get_mcn.argtypes = (c_void_p, ) + _LIB.discid_get_mcn.argtypes = (c_void_p,) _LIB.discid_get_mcn.restype = c_char_p except AttributeError: pass + def _get_mcn(self): - """Gets the current Media Catalogue Number (MCN/UPC/EAN) - """ + """Gets the current Media Catalogue Number (MCN/UPC/EAN)""" assert self._success if "mcn" in self._requested_features: try: @@ -274,7 +280,6 @@ def _get_mcn(self): else: return None - @property def id(self): """This is the MusicBrainz :musicbrainz:`Disc ID`, @@ -368,15 +373,13 @@ def mcn(self): @property def tracks(self): - """A list of :class:`Track` objects for this Disc. - """ + """A list of :class:`Track` objects for this Disc.""" tracks = [] assert self._success for number in range(self.first_track_num, self.last_track_num + 1): tracks.append(Track(self, number)) return tracks - @property def cddb_query_string(self): """A CDDB query string suitable for querying CDDB servers. @@ -394,12 +397,11 @@ def cddb_query_string(self): ) return cddb_query_string - - _LIB.discid_free.argtypes = (c_void_p, ) + _LIB.discid_free.argtypes = (c_void_p,) _LIB.discid_free.restype = None + def _free(self): - """This will free the internal allocated memory for the object. - """ + """This will free the internal allocated memory for the object.""" _LIB.discid_free(self._handle) self._handle = None diff --git a/discid/libdiscid.py b/discid/libdiscid.py index 7bf040e..07feab3 100644 --- a/discid/libdiscid.py +++ b/discid/libdiscid.py @@ -20,10 +20,10 @@ The code that works with Disc objects is in disc.py """ +import ctypes import os import sys -import ctypes -from ctypes import c_void_p, c_char_p +from ctypes import c_char_p, c_void_p from ctypes.util import find_library from discid.util import _decode @@ -33,16 +33,18 @@ def _find_library(name, version=0): - """Find a library by base-name and major version - """ - windows_names = ["%s.dll" % name, "lib%s.dll" % name, - "lib%s-%d.dll" % (name, version)] + """Find a library by base-name and major version""" + windows_names = [ + "%s.dll" % name, + "lib%s.dll" % name, + "lib%s-%d.dll" % (name, version), + ] lib_file = None # This seems to be necessary in a bundle/dmg if sys.platform == "darwin": - lib_name = '../Frameworks/lib%s.%d.dylib' % (name, version) + lib_name = "../Frameworks/lib%s.%d.dylib" % (name, version) if os.path.isfile(lib_name): lib_file = lib_name @@ -92,9 +94,9 @@ def _find_library(name, version=0): return lib_file + def _open_library(lib_name): - """Open a library by name or location - """ + """Open a library by name or location""" try: return ctypes.cdll.LoadLibrary(lib_name) except OSError as exc: @@ -104,19 +106,20 @@ def _open_library(lib_name): else: raise + _LIB_NAME = _find_library(_LIB_BASE_NAME, _LIB_MAJOR_VERSION) _LIB = _open_library(_LIB_NAME) - try: _LIB.discid_get_version_string.argtypes = () _LIB.discid_get_version_string.restype = c_char_p except AttributeError: pass + + def _get_version_string(): - """Get the version string of libdiscid - """ + """Get the version string of libdiscid""" try: version_string = _LIB.discid_get_version_string() except AttributeError: @@ -124,8 +127,11 @@ def _get_version_string(): else: return _decode(version_string) + _LIB.discid_get_default_device.argtypes = () _LIB.discid_get_default_device.restype = c_char_p + + def get_default_device(): """The default device to use for :func:`read` on this platform given as a :obj:`str ` object. @@ -133,16 +139,18 @@ def get_default_device(): device = _LIB.discid_get_default_device() return _decode(device) + try: - _LIB.discid_get_feature_list.argtypes = (c_void_p, ) + _LIB.discid_get_feature_list.argtypes = (c_void_p,) _LIB.discid_get_feature_list.restype = None except AttributeError: _features_available = False else: _features_available = True + + def _get_features(): - """Get the supported features for the platform. - """ + """Get the supported features for the platform.""" features = [] if _features_available: c_features = (c_char_p * 32)() @@ -152,7 +160,7 @@ def _get_features(): features.append(_decode(feature)) else: # libdiscid <= 0.4.0 - features = ["read"] # no generic platform yet + features = ["read"] # no generic platform yet try: # test for ISRC/MCN API (introduced 0.3.0) _LIB.discid_get_mcn # noqa: B018 (useless-expression) @@ -160,15 +168,18 @@ def _get_features(): pass else: # ISRC/MCN API found -> libdiscid = 0.3.x - if (sys.platform.startswith("linux") and - not os.path.isfile("/usr/lib/libdiscid.so.0.3.0") - and not os.path.isfile("/usr/lib64/libdiscid.so.0.3.0")): + if ( + sys.platform.startswith("linux") + and not os.path.isfile("/usr/lib/libdiscid.so.0.3.0") + and not os.path.isfile("/usr/lib64/libdiscid.so.0.3.0") + ): features += ["mcn", "isrc"] elif sys.platform in ["darwin", "win32"]: features += ["mcn", "isrc"] return features + LIBDISCID_VERSION_STRING = _get_version_string() FEATURES = _get_features() diff --git a/discid/track.py b/discid/track.py index 1984b92..f01d903 100644 --- a/discid/track.py +++ b/discid/track.py @@ -15,18 +15,16 @@ # # Please submit bug reports to GitHub: # https://github.com/metabrainz/python-discid/issues -"""Track class -""" +"""Track class""" -from ctypes import c_int, c_void_p, c_char_p +from ctypes import c_char_p, c_int, c_void_p from discid.libdiscid import _LIB from discid.util import _decode, _sectors_to_seconds class Track(object): - """Track objects are part of the :class:`Disc` class. - """ + """Track objects are part of the :class:`Disc` class.""" def __init__(self, disc, number): self._disc = disc @@ -39,12 +37,14 @@ def __str__(self): _LIB.discid_get_track_offset.argtypes = (c_void_p, c_int) _LIB.discid_get_track_offset.restype = c_int + def _get_track_offset(self): assert self._disc._success return _LIB.discid_get_track_offset(self._disc._handle, self.number) _LIB.discid_get_track_length.argtypes = (c_void_p, c_int) _LIB.discid_get_track_length.restype = c_int + def _get_track_length(self): assert self._disc._success return _LIB.discid_get_track_length(self._disc._handle, self.number) @@ -54,12 +54,12 @@ def _get_track_length(self): _LIB.discid_get_track_isrc.restype = c_char_p except AttributeError: pass + def _get_track_isrc(self): assert self._disc._success if "isrc" in self._disc._requested_features: try: - result = _LIB.discid_get_track_isrc(self._disc._handle, - self.number) + result = _LIB.discid_get_track_isrc(self._disc._handle, self.number) except AttributeError: return None else: @@ -67,7 +67,6 @@ def _get_track_isrc(self): else: return None - @property def number(self): """The track number""" diff --git a/discid/util.py b/discid/util.py index fd4c22e..9325b35 100644 --- a/discid/util.py +++ b/discid/util.py @@ -15,33 +15,33 @@ # # Please submit bug reports to GitHub: # https://github.com/metabrainz/python-discid/issues -"""utility functions -""" +"""utility functions""" import math SECTORS_PER_SECOND = 75 -def _encode(string: str|bytes): - """Encode (unicode) string to byte string - """ + +def _encode(string: str | bytes): + """Encode (unicode) string to byte string""" if isinstance(string, str): return string.encode() elif isinstance(string, bytes): return string - raise TypeError('Unexpected type, expected string or bytes') + raise TypeError("Unexpected type, expected string or bytes") # UnicodeDecodeError (Python 2) is NOT caught # device names should be ASCII -def _decode(byte_string: bytes|str): - """Decode byte string to (unicode) string - """ + +def _decode(byte_string: bytes | str): + """Decode byte string to (unicode) string""" # this test for bytes works on Python 2 and 3 if isinstance(byte_string, bytes): return byte_string.decode() elif isinstance(byte_string, str): return byte_string - raise TypeError('Unexpected type, expected string or bytes') + raise TypeError("Unexpected type, expected string or bytes") + def _sectors_to_seconds(sectors): """Round sectors to seconds like done on MusicBrainz Server diff --git a/doc/conf.py b/doc/conf.py index c61a74d..fe719bf 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -1,18 +1,23 @@ import ctypes -import sys import os +import sys # to gather version information import discid -sys.path.insert(0, os.path.abspath('.')) # for extensions -sys.path.insert(0, os.path.abspath('..')) # for the code +sys.path.insert(0, os.path.abspath(".")) # for extensions +sys.path.insert(0, os.path.abspath("..")) # for the code # -- Mock libdiscid loading ---------------------------------------------------- + class Mock(object): - def __call__(self, *args): return Mock() - def __getattr__(cls, name): return Mock() + def __call__(self, *args): + return Mock() + + def __getattr__(cls, name): + return Mock() + ctypes.cdll.LoadLibrary = Mock() @@ -21,16 +26,18 @@ def __getattr__(cls, name): return Mock() needs_sphinx = "1.0" extensions = [ - 'sphinx.ext.autodoc', 'sphinx.ext.coverage', - 'sphinx.ext.extlinks', 'sphinx.ext.intersphinx' + "sphinx.ext.autodoc", + "sphinx.ext.coverage", + "sphinx.ext.extlinks", + "sphinx.ext.intersphinx", ] -source_suffix = '.rst' -master_doc = 'index' -exclude_patterns = ['_build'] +source_suffix = ".rst" +master_doc = "index" +exclude_patterns = ["_build"] # General information about the project. -project = u'python-discid' -copyright = u'2013, Johannes Dewender' +project = "python-discid" +copyright = "2013, Johannes Dewender" # The short X.Y version / base version version = ".".join(discid.__version__.split("-")[0].split(".")[0:2]) # The full version, including alpha/beta/rc tags. @@ -46,37 +53,39 @@ def __getattr__(cls, name): return Mock() download_url = "%s/v%s.%%s" % (download_base, release) extlinks = { - 'source_download': (download_url, '%s'), - 'issue': ('https://github.com/metabrainz/python-discid/issues/%s', '#%s'), - 'musicbrainz': ('http://musicbrainz.org/doc/%s', '%s'), + "source_download": (download_url, "%s"), + "issue": ("https://github.com/metabrainz/python-discid/issues/%s", "#%s"), + "musicbrainz": ("http://musicbrainz.org/doc/%s", "%s"), } # there seems to be no way to prefer latest python documentation intersphinx_mapping = { - 'python': ('http://python.readthedocs.org/en/latest/', None), - 'musicbrainzngs': - ('http://python-musicbrainzngs.readthedocs.org/en/latest/', None), + "python": ("http://python.readthedocs.org/en/latest/", None), + "musicbrainzngs": ("http://python-musicbrainzngs.readthedocs.org/en/latest/", None), } rst_prolog = """ .. currentmodule:: discid """ -rst_epilog = """ +rst_epilog = ( + """ .. |current| replace:: %s -""" % current +""" + % current +) # -- Options for HTML output --------------------------------------------------- -html_theme = 'sphinx_rtd_theme' +html_theme = "sphinx_rtd_theme" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. html_theme_options = { - 'collapse_navigation': True, - 'navigation_depth': 2, - 'version_selector': True, + "collapse_navigation": True, + "navigation_depth": 2, + "version_selector": True, } html_title = "%s %s documentation" % (project, current) @@ -85,18 +94,22 @@ def __getattr__(cls, name): return Mock() # -- Options for LaTeX output -------------------------------------------------- latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -#'papersize': 'letterpaper', - -# The font size ('10pt', '11pt' or '12pt'). -#'pointsize': '10pt', + # The paper size ('letterpaper' or 'a4paper'). + #'papersize': 'letterpaper', + # The font size ('10pt', '11pt' or '12pt'). + #'pointsize': '10pt', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ - ('index', 'python-discid.tex', u'python-discid Documentation', - u'Johannes Dewender', 'manual'), + ( + "index", + "python-discid.tex", + "python-discid Documentation", + "Johannes Dewender", + "manual", + ), ] latex_domain_indices = False @@ -106,8 +119,7 @@ def __getattr__(cls, name): return Mock() # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - ('index', 'python-discid', u'python-discid Documentation', - [u'Johannes Dewender'], 1) + ("index", "python-discid", "python-discid Documentation", ["Johannes Dewender"], 1) ] # -- Options for Texinfo output ------------------------------------------------ @@ -116,9 +128,15 @@ def __getattr__(cls, name): return Mock() # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - ('index', 'python-discid', u'python-discid Documentation', - u'Johannes Dewender', 'python-discid', 'One line description of project.', - 'Miscellaneous'), + ( + "index", + "python-discid", + "python-discid Documentation", + "Johannes Dewender", + "python-discid", + "One line description of project.", + "Miscellaneous", + ), ] texinfo_domain_indices = False diff --git a/examples.py b/examples.py index 28c2cbc..f2f8225 100755 --- a/examples.py +++ b/examples.py @@ -5,8 +5,9 @@ # this will load Libdiscid import discid + def simple_example(): - disc = discid.read() # use default device + disc = discid.read() # use default device print("id: %s" % disc.id) print("used %s as device" % discid.get_default_device()) print("submit with:\n%s" % disc.submission_url) @@ -17,10 +18,13 @@ def _length_str(seconds, sectors): seconds = seconds % 3600 if hours: return "{h}:{m:>02}:{s:>02} ({sectors:>6})".format( - h=hours, m=(seconds // 60), s=(seconds % 60), sectors=sectors) + h=hours, m=(seconds // 60), s=(seconds % 60), sectors=sectors + ) else: return " {m:>2}:{s:>02} ({sectors:>6})".format( - m=(seconds // 60), s=(seconds % 60), sectors=sectors) + m=(seconds // 60), s=(seconds % 60), sectors=sectors + ) + def complex_example(): device_name = discid.get_default_device() @@ -31,11 +35,15 @@ def complex_example(): print("length:\t%s" % _length_str(disc.seconds, disc.sectors)) for track in disc.tracks: length = _length_str(track.seconds, track.sectors) - print("{num:>2}: {offset:>6} {len}\tISRC: {isrc:13}".format( - num=track.number, offset=track.offset, len=length, isrc=track.isrc)) + print( + "{num:>2}: {offset:>6} {len}\tISRC: {isrc:13}".format( + num=track.number, offset=track.offset, len=length, isrc=track.isrc + ) + ) + if __name__ == "__main__": - #simple_example() + # simple_example() complex_example() # vim:set shiftwidth=4 smarttab expandtab: diff --git a/pyproject.toml b/pyproject.toml index ef52bff..adc07a0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,7 +43,6 @@ dev = [ [tool.ruff] src=["discid"] -line-length=120 [tool.ruff.lint] select = ["E", "F", "W", "B"] diff --git a/test_discid.py b/test_discid.py index bb870ff..9974ce7 100755 --- a/test_discid.py +++ b/test_discid.py @@ -10,31 +10,55 @@ import discid.util test_discs = [ - { - "name": "Guano Apes - Don't give Me Names, without last data track", - "first": 1, - "last" : 15, - "sectors": 258725, - "offsets": [150, 17510, 33275, 45910, - 57805, 78310, 94650,109580, 132010, - 149160, 165115, 177710, 203325, 215555, 235590], - "id": "TqvKjMu7dMliSfmVEBtrL7sBSno-", - "freedb": "b60d770f" - }, - { - "name": "Lunar - There Is No 1, first track is 2", - "first": 2, - "last" : 11, - "sectors": 225781, - "offsets": [150, 11512, 34143, 50747, 63640, 98491, - 123534, 174410, 195438, 201127], - "id": "6RDuz0d7.M5SVMLe1z4DP0yaEC8-", - "freedb": "840bc20b" - }, - ] + { + "name": "Guano Apes - Don't give Me Names, without last data track", + "first": 1, + "last": 15, + "sectors": 258725, + "offsets": [ + 150, + 17510, + 33275, + 45910, + 57805, + 78310, + 94650, + 109580, + 132010, + 149160, + 165115, + 177710, + 203325, + 215555, + 235590, + ], + "id": "TqvKjMu7dMliSfmVEBtrL7sBSno-", + "freedb": "b60d770f", + }, + { + "name": "Lunar - There Is No 1, first track is 2", + "first": 2, + "last": 11, + "sectors": 225781, + "offsets": [ + 150, + 11512, + 34143, + 50747, + 63640, + 98491, + 123534, + 174410, + 195438, + 201127, + ], + "id": "6RDuz0d7.M5SVMLe1z4DP0yaEC8-", + "freedb": "840bc20b", + }, +] -class TestModulePrivate(unittest.TestCase): +class TestModulePrivate(unittest.TestCase): # lots of encoding tests # not part of the actual API, but this is quite different in Python 2/3 def test_encode(self): @@ -53,15 +77,14 @@ def test_decode(self): def test_encoding(self): string = "test" - self.assertEqual(discid.util._decode(discid.util._encode(string)), - string) + self.assertEqual(discid.util._decode(discid.util._encode(string)), string) bytestring = b"test" - self.assertEqual(discid.util._encode(discid.util._decode(bytestring)), - bytestring) + self.assertEqual( + discid.util._encode(discid.util._decode(bytestring)), bytestring + ) class TestModule(unittest.TestCase): - def test_version_string(self): version_string = discid.LIBDISCID_VERSION_STRING self.assertTrue(version_string is not None, "No version string given") @@ -92,8 +115,7 @@ def test_put_fail(self): # not enough offsets self.assertRaises(discid.TOCError, discid.put, 1, 2, 150, [150]) # too many offsets - self.assertRaises(discid.TOCError, - discid.put, 1, 2, 1000, [150, 500, 750]) + self.assertRaises(discid.TOCError, discid.put, 1, 2, 1000, [150, 500, 750]) # total sectors / offset mismatch self.assertRaises(discid.TOCError, discid.put, 1, 2, 150, [150, 500]) # too many tracks @@ -101,8 +123,12 @@ def test_put_fail(self): def test_put_success(self): for test_disc in test_discs: - disc = discid.put(test_disc["first"], test_disc["last"], - test_disc["sectors"], test_disc["offsets"]) + disc = discid.put( + test_disc["first"], + test_disc["last"], + test_disc["sectors"], + test_disc["offsets"], + ) self.assertEqual(disc.id, test_disc["id"]) self.assertEqual(disc.freedb_id, test_disc["freedb"]) self.assertEqual(disc.first_track_num, test_disc["first"]) @@ -110,29 +136,36 @@ def test_put_success(self): self.assertEqual(disc.sectors, test_disc["sectors"]) track_offsets = [track.offset for track in disc.tracks] self.assertEqual(track_offsets, test_disc["offsets"]) - self.assertEqual(disc.sectors, - disc.tracks[-1].offset + disc.tracks[-1].sectors) + self.assertEqual( + disc.sectors, disc.tracks[-1].offset + disc.tracks[-1].sectors + ) self.assertEqual(disc.seconds, math.floor((disc.sectors / 75.0) + 0.5)) self.assertEqual(type(disc.seconds), int) for track in disc.tracks: - self.assertEqual(track.seconds, - math.floor((track.sectors / 75.0) + 0.5)) + self.assertEqual( + track.seconds, math.floor((track.sectors / 75.0) + 0.5) + ) self.assertEqual(type(track.seconds), int) - toc_string = [test_disc["first"], disc.last_track_num, disc.sectors] + track_offsets + toc_string = [ + test_disc["first"], + disc.last_track_num, + disc.sectors, + ] + track_offsets toc_string = " ".join(map(str, toc_string)) self.assertEqual(disc.toc_string, toc_string) - cddb_query_string = [disc.freedb_id, disc.last_track_num] + track_offsets + [disc.seconds] + cddb_query_string = ( + [disc.freedb_id, disc.last_track_num] + track_offsets + [disc.seconds] + ) cddb_query_string = " ".join(map(str, cddb_query_string)) self.assertEqual(disc.cddb_query_string, cddb_query_string) @unittest.skipUnless( - os.environ.get('PYTHON_DISCID_TEST_DEVICE'), + os.environ.get("PYTHON_DISCID_TEST_DEVICE"), "tests require physical CD drive with inserted disc", ) class TestDisc(unittest.TestCase): - """Test reading the disc currently in the drive - """ + """Test reading the disc currently in the drive""" def test_default_device(self): # Can't be empty, in contrast to the test in TestModule @@ -145,22 +178,23 @@ def test_features(self): self.assertTrue(features, "No feature list given") def test_read_simple(self): - disc = discid.read() # read from default drive + disc = discid.read() # read from default drive self.assertEqual(len(disc.id), 28, "Invalid Disc ID") self.assertEqual(len(disc.freedb_id), 8, "Invalid FreeDB Disc ID") self.assertTrue(disc.submission_url, "Invalid submission url") self.assertTrue(disc.toc_string, "Invalid toc string") - self.assertEqual(disc.last_track_num, len(disc.tracks), - "Wrong amount of tracks") - self.assertEqual(disc.sectors, - disc.tracks[-1].offset + disc.tracks[-1].sectors) + self.assertEqual( + disc.last_track_num, len(disc.tracks), "Wrong amount of tracks" + ) + self.assertEqual(disc.sectors, disc.tracks[-1].offset + disc.tracks[-1].sectors) for track in disc.tracks: self.assertTrue(track.offset <= disc.sectors, "Invalid offset") if track.number > 1: - previous_offset = disc.tracks[track.number-2].offset - self.assertTrue(track.offset >= previous_offset, - "Invalid offset series") + previous_offset = disc.tracks[track.number - 2].offset + self.assertTrue( + track.offset >= previous_offset, "Invalid offset series" + ) # additional features should be unset, not empty self.assertTrue(disc.mcn is None) @@ -181,29 +215,26 @@ def test_read_simple(self): disc = discid.put(first, last, sectors, track_offsets) self.assertEqual(disc.id, disc_id, "different id after put") - self.assertEqual(disc.freedb_id, freedb_id, - "different freedb id after put") - self.assertEqual(disc.submission_url, submission_url, - "different submission_url after put") - self.assertEqual(disc.toc_string, toc_string, - "different toc_string after put") - self.assertEqual(disc.first_track_num, first, - "different first track after put") - self.assertEqual(disc.last_track_num, last, - "different last track after put") - self.assertEqual(disc.sectors, sectors, - "different sector count after put") + self.assertEqual(disc.freedb_id, freedb_id, "different freedb id after put") + self.assertEqual( + disc.submission_url, submission_url, "different submission_url after put" + ) + self.assertEqual(disc.toc_string, toc_string, "different toc_string after put") + self.assertEqual(disc.first_track_num, first, "different first track after put") + self.assertEqual(disc.last_track_num, last, "different last track after put") + self.assertEqual(disc.sectors, sectors, "different sector count after put") new_offsets = [track.offset for track in disc.tracks] - self.assertEqual(new_offsets, track_offsets, - "different offsets after put") + self.assertEqual(new_offsets, track_offsets, "different offsets after put") new_sectors = [track.sectors for track in disc.tracks] - self.assertEqual(new_sectors, track_sectors, - "different lengths after put") - self.assertEqual(disc.cddb_query_string, cddb_query_string, - "different cddb_query_string after put") + self.assertEqual(new_sectors, track_sectors, "different lengths after put") + self.assertEqual( + disc.cddb_query_string, + cddb_query_string, + "different cddb_query_string after put", + ) def test_read_features(self): - disc = discid.read(features=["mcn", "isrc"]) # read from default drive + disc = discid.read(features=["mcn", "isrc"]) # read from default drive self.assertEqual(len(disc.id), 28, "Invalid Disc ID") self.assertTrue(disc.submission_url, "Invalid submission url") self.assertTrue(disc.toc_string, "Invalid toc string") @@ -221,10 +252,14 @@ def test_read_features(self): def test_read_put(self): # a read followed with a put, which should clear the features - disc = discid.read(features=["mcn", "isrc"]) # read from default drive + disc = discid.read(features=["mcn", "isrc"]) # read from default drive test_disc = test_discs[0] - disc = discid.put(test_disc["first"], test_disc["last"], - test_disc["sectors"], test_disc["offsets"]) + disc = discid.put( + test_disc["first"], + test_disc["last"], + test_disc["sectors"], + test_disc["offsets"], + ) self.assertTrue(disc.mcn is None) for track in disc.tracks: self.assertTrue(track.isrc is None) From f1e0cd79971e48e8d764b93e1d5e7136430ddde2 Mon Sep 17 00:00:00 2001 From: Philipp Wolfer Date: Mon, 19 Jan 2026 11:43:58 +0100 Subject: [PATCH 2/3] Added .git-blame-ignore-revs to ignore reformatting commit --- .git-blame-ignore-revs | 1 + 1 file changed, 1 insertion(+) create mode 100644 .git-blame-ignore-revs diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 0000000..bc5ce28 --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1 @@ +81f388fe4ab7fe591d68cc3f14753247eaa4992d From a0f604942ed50baa4580098c78417c8366b4cc73 Mon Sep 17 00:00:00 2001 From: Philipp Wolfer Date: Mon, 19 Jan 2026 11:44:20 +0100 Subject: [PATCH 3/3] Run ruff format in pre-commit and CI workflow --- .github/workflows/lint.yaml | 4 ++++ .pre-commit-config.yaml | 1 + 2 files changed, 5 insertions(+) diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 60aba60..e1b5a95 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -15,3 +15,7 @@ jobs: uses: astral-sh/ruff-action@v3 with: args: "check --output-format=github" + - name: Ruff format check + uses: astral-sh/ruff-action@v3 + with: + args: "format --diff" diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a96bda3..7a94170 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,6 +5,7 @@ repos: hooks: - id: ruff-check args: [--fix] + - id: ruff-format - repo: local hooks: - id: pytest