Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-pyacoustid for openSUSE:Factory checked in at 2026-04-22 17:20:55 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-pyacoustid (Old) and /work/SRC/openSUSE:Factory/.python-pyacoustid.new.11940 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-pyacoustid" Wed Apr 22 17:20:55 2026 rev:7 rq:1348799 version:1.3.1 Changes: -------- --- /work/SRC/openSUSE:Factory/python-pyacoustid/python-pyacoustid.changes 2025-06-04 20:29:22.183012191 +0200 +++ /work/SRC/openSUSE:Factory/.python-pyacoustid.new.11940/python-pyacoustid.changes 2026-04-22 17:20:56.856886812 +0200 @@ -1,0 +2,25 @@ +Tue Apr 21 07:00:26 UTC 2026 - John Paul Adrian Glaubitz <[email protected]> + +- Update to 1.3.1 + * [enhancement] Improves python docstring for chromaprint + * fix: return unsigned int32 for chromaprint_decode_fingerprint + * Feature: Join artist names by join phrase + * Update README.rst + * add fingerprint comparison to acoustid.py + * decode_fingerprint bugfixes + * Windows import library fix + * Add Python syntax highlighting to README.rst + * Modernize setup, add tests + * Fix inconsistent fingerprints + * Support Python 3.14 and update deps + * Fix PYTHON_VERSION in make_release +- Update BuildRequires from pyproject.toml + +------------------------------------------------------------------- +Tue Apr 21 06:50:04 UTC 2026 - John Paul Adrian Glaubitz <[email protected]> + +- Update to 1.3.1 + +- Use Python 3.11 on SLE-15 by default + +------------------------------------------------------------------- Old: ---- pyacoustid-1.3.0.tar.gz New: ---- pyacoustid-1.3.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-pyacoustid.spec ++++++ --- /var/tmp/diff_new_pack.ayuqvW/_old 2026-04-22 17:20:57.660920019 +0200 +++ /var/tmp/diff_new_pack.ayuqvW/_new 2026-04-22 17:20:57.664920184 +0200 @@ -1,7 +1,7 @@ # # spec file for package python-pyacoustid # -# Copyright (c) 2025 SUSE LLC +# Copyright (c) 2026 SUSE LLC and contributors # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -16,8 +16,9 @@ # +%{?sle15_python_module_pythons} Name: python-pyacoustid -Version: 1.3.0 +Version: 1.3.1 Release: 0 Summary: Bindings for Chromaprint acoustic fingerprinting and the Acoustid API License: MIT @@ -26,8 +27,8 @@ Source: https://files.pythonhosted.org/packages/source/p/pyacoustid/pyacoustid-%{version}.tar.gz BuildRequires: %{python_module audioread} BuildRequires: %{python_module pip} +BuildRequires: %{python_module poetry-core} BuildRequires: %{python_module requests} -BuildRequires: %{python_module setuptools} BuildRequires: %{python_module wheel} BuildRequires: fdupes BuildRequires: python-rpm-macros ++++++ pyacoustid-1.3.0.tar.gz -> pyacoustid-1.3.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyacoustid-1.3.0/MANIFEST.in new/pyacoustid-1.3.1/MANIFEST.in --- old/pyacoustid-1.3.0/MANIFEST.in 2019-05-25 14:44:51.000000000 +0200 +++ new/pyacoustid-1.3.1/MANIFEST.in 1970-01-01 01:00:00.000000000 +0100 @@ -1,6 +0,0 @@ -# Documentation. -include README.rst -include LICENSE -# Example scripts. -include aidmatch.py -include fpcalc.py diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyacoustid-1.3.0/PKG-INFO new/pyacoustid-1.3.1/PKG-INFO --- old/pyacoustid-1.3.0/PKG-INFO 2023-09-12 20:00:04.142308500 +0200 +++ new/pyacoustid-1.3.1/PKG-INFO 1970-01-01 01:00:00.000000000 +0100 @@ -1,17 +1,27 @@ -Metadata-Version: 2.1 +Metadata-Version: 2.4 Name: pyacoustid -Version: 1.3.0 -Summary: bindings for Chromaprint acoustic fingerprinting and the Acoustid API -Home-page: https://github.com/sampsyo/pyacoustid +Version: 1.3.1 +Summary: Bindings for Chromaprint acoustic fingerprinting and the Acoustid API +License-Expression: MIT +License-File: LICENSE Author: Adrian Sampson Author-email: [email protected] -License: MIT -Platform: ALL -Classifier: Topic :: Multimedia :: Sound/Audio :: Conversion +Requires-Python: >=3.10 Classifier: Intended Audience :: Developers -Classifier: Programming Language :: Python :: 2 +Classifier: License :: OSI Approved :: MIT License Classifier: Programming Language :: Python :: 3 -License-File: LICENSE +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 +Classifier: Programming Language :: Python :: 3.14 +Classifier: Topic :: Multimedia :: Sound/Audio :: Conversion +Requires-Dist: audioread +Requires-Dist: requests +Project-URL: Bug Tracker, https://github.com/beetbox/pyacoustid/issues +Project-URL: Homepage, https://github.com/beetbox/pyacoustid +Project-URL: Repository, https://github.com/beetbox/pyacoustid +Description-Content-Type: text/x-rst Chromaprint and Acoustid for Python =================================== @@ -28,10 +38,9 @@ Installation ------------ -This library works with Python 2 (2.7+, possibly also 2.6) and Python 3 -(3.3+). +This library works with Python 3.10+. -First, install the `Chromaprint`_ fingerprinting library by `Lukas Lalinsky`__. +First, install the `Chromaprint`_ fingerprinting library by `Lukáš Lalinský`__. (The library itself depends on an FFT library, but it's smart enough to use an algorithm from software you probably already have installed; see the Chromaprint page for details.) This module can use either the Chromaprint dynamic library or @@ -74,7 +83,9 @@ ------------------ The simplest way to use pyacoustid to identify audio files is to call the -``match`` function:: +``match`` function: + +.. code-block:: python >>> import acoustid >>> for score, recording_id, title, artist in acoustid.match(apikey, path): @@ -203,7 +214,7 @@ 0.4 Fingerprinting can now fall back to using the ``fpcalc`` command-line tool instead of the Chromaprint dynamic library so the library can be used with - the binary distributions (thanks to Lukas Lalinsky). + the binary distributions (thanks to Lukáš Lalinský). Fingerprint submission (thanks to Alastair Porter). Data chunks can now be buffers as well as bytestrings (fixes compatibility with pymad). @@ -226,9 +237,9 @@ Credits ------- -This library is by Adrian Sampson. Chromaprint and Acoustid are by `Lukas -Lalinsky`__. This package includes the original `ctypes`_-based bindings -written by Lukas. The entire library is made available under the `MIT license`_. +This library is by Adrian Sampson. Chromaprint and Acoustid are by `Lukáš +Lalinský`__. This package includes the original `ctypes`_-based bindings +written by Lukáš. The entire library is made available under the `MIT license`_. pyacoustid was written to be used with `beets`_, which you should probably check out. @@ -236,3 +247,4 @@ .. _ctypes: http://docs.python.org/library/ctypes.html .. _beets: http://beets.radbox.org/ .. _MIT license: http://www.opensource.org/licenses/mit-license.php + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyacoustid-1.3.0/README.rst new/pyacoustid-1.3.1/README.rst --- old/pyacoustid-1.3.0/README.rst 2023-09-12 19:58:56.000000000 +0200 +++ new/pyacoustid-1.3.1/README.rst 1970-01-01 01:00:00.000000000 +0100 @@ -13,8 +13,7 @@ Installation ------------ -This library works with Python 2 (2.7+, possibly also 2.6) and Python 3 -(3.3+). +This library works with Python 3.10+. First, install the `Chromaprint`_ fingerprinting library by `Lukáš Lalinský`__. (The library itself depends on an FFT library, but it's smart enough to use an @@ -59,7 +58,9 @@ ------------------ The simplest way to use pyacoustid to identify audio files is to call the -``match`` function:: +``match`` function: + +.. code-block:: python >>> import acoustid >>> for score, recording_id, title, artist in acoustid.match(apikey, path): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyacoustid-1.3.0/acoustid.py new/pyacoustid-1.3.1/acoustid.py --- old/pyacoustid-1.3.0/acoustid.py 2023-09-12 19:58:56.000000000 +0200 +++ new/pyacoustid-1.3.1/acoustid.py 1970-01-01 01:00:00.000000000 +0100 @@ -12,15 +12,12 @@ # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. -from __future__ import division -from __future__ import absolute_import -from typing import List - -import os -import json -import requests import contextlib import errno +import json +import os + +import requests try: import audioread @@ -34,24 +31,25 @@ have_chromaprint = True except ImportError: have_chromaprint = False +import gzip import subprocess import threading import time -import gzip from io import BytesIO -API_BASE_URL = 'http://api.acoustid.org/v2/' -DEFAULT_META = ['recordings'] +API_BASE_URL = "http://api.acoustid.org/v2/" +DEFAULT_META = ["recordings"] REQUEST_INTERVAL = 0.33 # 3 requests/second. MAX_AUDIO_LENGTH = 120 # Seconds. -FPCALC_COMMAND = 'fpcalc' -FPCALC_ENVVAR = 'FPCALC' +FPCALC_COMMAND = "fpcalc" +FPCALC_ENVVAR = "FPCALC" MAX_BIT_ERROR = 2 # comparison settings MAX_ALIGN_OFFSET = 120 # Exceptions. + class AcoustidError(Exception): """Base for exceptions in this module.""" @@ -76,6 +74,7 @@ sent by the acoustid server, then the ``code`` field contains the acoustid error code. """ + def __init__(self, message, response=None): """Create an error for the given HTTP response body, if provided, with the ``message`` as a fallback. @@ -87,48 +86,50 @@ except ValueError: pass else: - if isinstance(data.get('error'), dict): - error = data['error'] - if 'message' in error: - message = error['message'] - if 'code' in error: - self.code = error['code'] + if isinstance(data.get("error"), dict): + error = data["error"] + if "message" in error: + message = error["message"] + if "code" in error: + self.code = error["code"] - super(WebServiceError, self).__init__(message) + super().__init__(message) self.message = message # Endpoint configuration. + def set_base_url(url): """Set the URL of the API server to query.""" - if not url.endswith('/'): - url += '/' + if not url.endswith("/"): + url += "/" global API_BASE_URL API_BASE_URL = url def _get_lookup_url(): """Get the URL of the lookup API endpoint.""" - return API_BASE_URL + 'lookup' + return API_BASE_URL + "lookup" def _get_submit_url(): """Get the URL of the submission API endpoint.""" - return API_BASE_URL + 'submit' + return API_BASE_URL + "submit" def _get_submission_status_url(): """Get the URL of the submission status API endpoint.""" - return API_BASE_URL + 'submission_status' + return API_BASE_URL + "submission_status" # Compressed HTTP request bodies. + def _compress(data): """Compress a bytestring to a gzip archive.""" sio = BytesIO() - with contextlib.closing(gzip.GzipFile(fileobj=sio, mode='wb')) as f: + with contextlib.closing(gzip.GzipFile(fileobj=sio, mode="wb")) as f: f.write(data) return sio.getvalue() @@ -141,20 +142,22 @@ def add_headers(self, request, **kwargs): body = request.body if not isinstance(body, bytes): - body = body.encode('utf8') + body = body.encode("utf8") request.prepare_body(_compress(body), None) - request.headers['Content-Encoding'] = 'gzip' + request.headers["Content-Encoding"] = "gzip" # Utilities. -class _rate_limit(object): # noqa: N801 + +class _rate_limit: # noqa: N801 """A decorator that limits the rate at which the function may be called. The rate is controlled by the REQUEST_INTERVAL module-level constant; set the value to zero to disable rate limiting. The limiting is thread-safe; only one thread may be in the function at a time (acts like a monitor in this sense). """ + def __init__(self, fun): self.fun = fun self.last_call = 0.0 @@ -181,34 +184,30 @@ If the specified timeout passes, then raises a TimeoutError. """ headers = { - 'Accept-Encoding': 'gzip', - "Content-Type": "application/x-www-form-urlencoded" + "Accept-Encoding": "gzip", + "Content-Type": "application/x-www-form-urlencoded", } with requests.Session() as session: - session.mount('http://', CompressedHTTPAdapter()) + session.mount("http://", CompressedHTTPAdapter()) try: - if isinstance(params.get('meta'), list): - params['meta'] = ' '.join(params['meta']) - response = session.post(url, - data=params, - headers=headers, - timeout=timeout) + if isinstance(params.get("meta"), list): + params["meta"] = " ".join(params["meta"]) + response = session.post(url, data=params, headers=headers, timeout=timeout) except requests.exceptions.RequestException as exc: - raise WebServiceError("HTTP request failed: {0}".format(exc)) + raise WebServiceError(f"HTTP request failed: {exc}") except requests.exceptions.ReadTimeout: - raise WebServiceError( - "HTTP request timed out ({0}s)".format(timeout) - ) + raise WebServiceError(f"HTTP request timed out ({timeout}s)") try: return response.json() except ValueError: - raise WebServiceError('response is not valid JSON') + raise WebServiceError("response is not valid JSON") # Main API. + def fingerprint(samplerate, channels, pcmiter, maxlength=MAX_AUDIO_LENGTH): """Fingerprint audio data given its sample rate and number of channels. pcmiter should be an iterable containing blocks of PCM @@ -222,13 +221,21 @@ fper = chromaprint.Fingerprinter() fper.start(samplerate, channels) - position = 0 # Samples of audio fed to the fingerprinter. - for block in pcmiter: - fper.feed(block) - position += len(block) // 2 # 2 bytes/sample. - if position >= endposition: + position = 0 + while position < endposition: + try: + block = next(pcmiter) + except StopIteration: + # No more data break + # Calculate remaining samples needed + remaining = endposition - position + # Feed only up to remaining samples + bytes_to_feed = min(len(block), remaining * 2) + fper.feed(block[:bytes_to_feed]) + position += bytes_to_feed // 2 + return fper.finish() except chromaprint.FingerprintError: raise FingerprintGenerationError("fingerprint calculation failed") @@ -242,11 +249,11 @@ tracks, compress, usermeta, sources. """ params = { - 'format': 'json', - 'client': apikey, - 'duration': int(duration), - 'fingerprint': fingerprint, - 'meta': meta, + "format": "json", + "client": apikey, + "duration": int(duration), + "fingerprint": fingerprint, + "meta": meta, } return _api_request(_get_lookup_url(), params, timeout) @@ -259,18 +266,18 @@ the last item is None. If the response is incomplete, raises a WebServiceError. """ - if data['status'] != 'ok': - raise WebServiceError("status: %s" % data['status']) - if 'results' not in data: + if data["status"] != "ok": + raise WebServiceError("status: {}".format(data["status"])) + if "results" not in data: raise WebServiceError("results not included") - for result in data['results']: - score = result['score'] - if 'recordings' not in result: + for result in data["results"]: + score = result["score"] + if "recordings" not in result: # No recording attached. This result is not very useful. continue - for recording in result['recordings']: + for recording in result["recordings"]: # Get the artist if available. artists = recording.get("artists") if artists: @@ -283,7 +290,7 @@ else: artist_name = None - yield score, recording['id'], recording.get('title'), artist_name + yield score, recording["id"], recording.get("title"), artist_name def _fingerprint_file_audioread(path, maxlength): @@ -302,38 +309,30 @@ fpcalc = os.environ.get(FPCALC_ENVVAR, FPCALC_COMMAND) command = [fpcalc, "-length", str(maxlength), path] try: - with open(os.devnull, 'wb') as devnull: - proc = subprocess.Popen(command, stdout=subprocess.PIPE, - stderr=devnull) + with open(os.devnull, "wb") as devnull: + proc = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=devnull) output, _ = proc.communicate() except OSError as exc: if exc.errno == errno.ENOENT: raise NoBackendError("fpcalc not found") else: - raise FingerprintGenerationError("fpcalc invocation failed: %s" % - str(exc)) - except UnicodeEncodeError: - # Due to a bug in Python 2's subprocess on Windows, Unicode - # filenames can fail to encode on that platform. See: - # http://bugs.python.org/issue1759845 - raise FingerprintGenerationError("argument encoding failed") + raise FingerprintGenerationError(f"fpcalc invocation failed: {exc!s}") retcode = proc.poll() if retcode: - raise FingerprintGenerationError("fpcalc exited with status %i" % - retcode) + raise FingerprintGenerationError(f"fpcalc exited with status {retcode}") duration = fp = None for line in output.splitlines(): try: - parts = line.split(b'=', 1) + parts = line.split(b"=", 1) except ValueError: raise FingerprintGenerationError("malformed fpcalc output") - if parts[0] == b'DURATION': + if parts[0] == b"DURATION": try: duration = float(parts[1]) except ValueError: raise FingerprintGenerationError("fpcalc duration not numeric") - elif parts[0] == b'FINGERPRINT': + elif parts[0] == b"FINGERPRINT": fp = parts[1] if duration is None or fp is None: @@ -356,10 +355,10 @@ def _popcount(x) -> int: """count 1s in binary encoding of x""" - return bin(x).count('1') + return bin(x).count("1") -def _match_fingerprints(a: List[int], b: List[int]) -> float: +def _match_fingerprints(a: list[int], b: list[int]) -> float: """Compare two Chromaprint fingerprints, given as numbers. For more details, see: @@ -402,8 +401,9 @@ return _match_fingerprints(a, b) -def match(apikey, path, meta=DEFAULT_META, parse=True, force_fpcalc=False, - timeout=None): +def match( + apikey, path, meta=DEFAULT_META, parse=True, force_fpcalc=False, timeout=None +): """Look up the metadata for an audio file. If ``parse`` is true, then ``parse_lookup_result`` is used to return an iterator over small tuple of relevant information; otherwise, the full parsed JSON @@ -443,9 +443,9 @@ data = [data] args = { - 'format': 'json', - 'client': apikey, - 'user': userkey, + "format": "json", + "client": apikey, + "user": userkey, } # Build up "field.#" parameters corresponding to the parameters @@ -458,16 +458,16 @@ d["duration"] = int(d["duration"]) for k, v in d.items(): - args["%s.%s" % (k, i)] = v + args[f"{k}.{i}"] = v response = _api_request(_get_submit_url(), args, timeout) - if response.get('status') != 'ok': + if response.get("status") != "ok": try: - code = response['error']['code'] - message = response['error']['message'] + code = response["error"]["code"] + message = response["error"]["message"] except KeyError: - raise WebServiceError("response: {0}".format(response)) - raise WebServiceError("error {0}: {1}".format(code, message)) + raise WebServiceError(f"response: {response}") + raise WebServiceError(f"error {code}: {message}") return response @@ -477,8 +477,8 @@ in the response object of a call to the ``submit`` endpoint. """ params = { - 'format': 'json', - 'client': apikey, - 'id': submission_id, + "format": "json", + "client": apikey, + "id": submission_id, } return _api_request(_get_submission_status_url(), params, timeout) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyacoustid-1.3.0/aidmatch.py new/pyacoustid-1.3.1/aidmatch.py --- old/pyacoustid-1.3.0/aidmatch.py 2016-08-01 04:52:05.000000000 +0200 +++ new/pyacoustid-1.3.1/aidmatch.py 1970-01-01 01:00:00.000000000 +0100 @@ -1,4 +1,3 @@ -from __future__ import print_function # This file is part of pyacoustid. # Copyright 2011, Adrian Sampson. # @@ -16,26 +15,15 @@ """Example script that identifies metadata for files specified on the command line. """ -import acoustid + import sys +import acoustid + # API key for this demo script only. Get your own API key at the # Acoustid Web for your application. # http://acoustid.org/ -API_KEY = 'cSpUJKpD' - - -# Python 2/3 Unicode compatibility: this `print_` function forces a -# unicode string into a byte string for printing on Python 2, avoiding -# errors in the process, and does nothing on Python 3, where -# stdout/stderr are text streams (and there's not much we can do about -# that). -if sys.version_info[0] < 3: - def print_(s): - print(s.encode(sys.stdout.encoding, 'replace')) -else: - def print_(s): - print(s) +API_KEY = "cSpUJKpD" def aidmatch(filename): @@ -48,7 +36,7 @@ print("fingerprint could not be calculated", file=sys.stderr) sys.exit(1) except acoustid.WebServiceError as exc: - print("web service request failed:", exc.message, file=sys.stderr) + print("web service request failed:", str(exc), file=sys.stderr) sys.exit(1) first = True @@ -57,10 +45,10 @@ first = False else: print() - print_('%s - %s' % (artist, title)) - print_('http://musicbrainz.org/recording/%s' % rid) - print_('Score: %i%%' % (int(score * 100))) + print(f"{artist} - {title}") + print(f"http://musicbrainz.org/recording/{rid}") + print(f"Score: {int(score * 100)}%") -if __name__ == '__main__': +if __name__ == "__main__": aidmatch(sys.argv[1]) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyacoustid-1.3.0/chromaprint.py new/pyacoustid-1.3.1/chromaprint.py --- old/pyacoustid-1.3.0/chromaprint.py 2023-09-12 19:58:56.000000000 +0200 +++ new/pyacoustid-1.3.1/chromaprint.py 1970-01-01 01:00:00.000000000 +0100 @@ -4,39 +4,31 @@ """Low-level ctypes wrapper from the chromaprint library.""" -import sys import ctypes import ctypes.util +import sys -if sys.version_info[0] >= 3: - BUFFER_TYPES = (memoryview, bytearray,) - BYTES_TYPE = bytes -elif sys.version_info[1] >= 7: - BUFFER_TYPES = (buffer, memoryview, bytearray,) # noqa: F821 - BYTES_TYPE = str -else: - BUFFER_TYPES = (buffer, bytearray,) # noqa: F821 - BYTES_TYPE = str +BUFFER_TYPES = (memoryview, bytearray) # Find the base library and declare prototypes. + def _guess_lib_name(): - if sys.platform == 'darwin': - return ('libchromaprint.1.dylib', 'libchromaprint.0.dylib') - elif sys.platform == 'win32': - return ('chromaprint.dll', 'libchromaprint.dll') - elif sys.platform == 'cygwin': - return ('libchromaprint.dll.a', 'cygchromaprint-1.dll', - 'cygchromaprint-0.dll') - return ('libchromaprint.so.1', 'libchromaprint.so.0') + if sys.platform == "darwin": + return ("libchromaprint.1.dylib", "libchromaprint.0.dylib") + elif sys.platform == "win32": + return ("chromaprint.dll", "libchromaprint.dll") + elif sys.platform == "cygwin": + return ("libchromaprint.dll.a", "cygchromaprint-1.dll", "cygchromaprint-0.dll") + return ("libchromaprint.so.1", "libchromaprint.so.0") def _load_library(name): """Try to load a dynamic library with ctypes, or return None if the library is not available. """ - if sys.platform == 'win32': + if sys.platform == "win32": # On Windows since Python 3.8, we need an extra call to # `find_library` to search standard library paths. name = ctypes.util.find_library(name) @@ -68,36 +60,54 @@ _libchromaprint.chromaprint_free.argtypes = (ctypes.c_void_p,) _libchromaprint.chromaprint_free.restype = None -_libchromaprint.chromaprint_start.argtypes = \ - (ctypes.c_void_p, ctypes.c_int, ctypes.c_int) +_libchromaprint.chromaprint_start.argtypes = ( + ctypes.c_void_p, + ctypes.c_int, + ctypes.c_int, +) _libchromaprint.chromaprint_start.restype = ctypes.c_int -_libchromaprint.chromaprint_feed.argtypes = \ - (ctypes.c_void_p, ctypes.POINTER(ctypes.c_char), ctypes.c_int) +_libchromaprint.chromaprint_feed.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(ctypes.c_char), + ctypes.c_int, +) _libchromaprint.chromaprint_feed.restype = ctypes.c_int _libchromaprint.chromaprint_finish.argtypes = (ctypes.c_void_p,) _libchromaprint.chromaprint_finish.restype = ctypes.c_int -_libchromaprint.chromaprint_get_fingerprint.argtypes = \ - (ctypes.c_void_p, ctypes.POINTER(ctypes.c_char_p)) +_libchromaprint.chromaprint_get_fingerprint.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(ctypes.c_char_p), +) _libchromaprint.chromaprint_get_fingerprint.restype = ctypes.c_int -_libchromaprint.chromaprint_decode_fingerprint.argtypes = \ - (ctypes.POINTER(ctypes.c_char), ctypes.c_int, - ctypes.POINTER(ctypes.POINTER(ctypes.c_uint32)), - ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int), ctypes.c_int) +_libchromaprint.chromaprint_decode_fingerprint.argtypes = ( + ctypes.POINTER(ctypes.c_char), + ctypes.c_int, + ctypes.POINTER(ctypes.POINTER(ctypes.c_uint32)), + ctypes.POINTER(ctypes.c_int), + ctypes.POINTER(ctypes.c_int), + ctypes.c_int, +) _libchromaprint.chromaprint_decode_fingerprint.restype = ctypes.c_int -_libchromaprint.chromaprint_encode_fingerprint.argtypes = \ - (ctypes.POINTER(ctypes.c_int32), ctypes.c_int, ctypes.c_int, - ctypes.POINTER(ctypes.POINTER(ctypes.c_char)), - ctypes.POINTER(ctypes.c_int), ctypes.c_int) +_libchromaprint.chromaprint_encode_fingerprint.argtypes = ( + ctypes.POINTER(ctypes.c_int32), + ctypes.c_int, + ctypes.c_int, + ctypes.POINTER(ctypes.POINTER(ctypes.c_char)), + ctypes.POINTER(ctypes.c_int), + ctypes.c_int, +) _libchromaprint.chromaprint_encode_fingerprint.restype = ctypes.c_int -_libchromaprint.chromaprint_hash_fingerprint.argtypes = \ - (ctypes.POINTER(ctypes.c_int32), ctypes.c_int, - ctypes.POINTER(ctypes.c_uint32)) +_libchromaprint.chromaprint_hash_fingerprint.argtypes = ( + ctypes.POINTER(ctypes.c_int32), + ctypes.c_int, + ctypes.POINTER(ctypes.c_uint32), +) _libchromaprint.chromaprint_hash_fingerprint.restype = ctypes.c_int _libchromaprint.chromaprint_dealloc.argtypes = (ctypes.c_void_p,) @@ -106,6 +116,7 @@ # Main interface. + class FingerprintError(Exception): """Raised when a call to the underlying library fails.""" @@ -118,8 +129,7 @@ raise FingerprintError() -class Fingerprinter(object): - +class Fingerprinter: ALGORITHM_TEST1 = 0 ALGORITHM_TEST2 = 1 ALGORITHM_TEST3 = 2 @@ -133,23 +143,18 @@ del self._ctx def start(self, sample_rate, num_channels): - """Initialize the fingerprinter with the given audio parameters. - """ - _check(_libchromaprint.chromaprint_start( - self._ctx, sample_rate, num_channels - )) + """Initialize the fingerprinter with the given audio parameters.""" + _check(_libchromaprint.chromaprint_start(self._ctx, sample_rate, num_channels)) def feed(self, data): """Send raw PCM audio data to the fingerprinter. Data may be either a bytestring or a buffer object. """ if isinstance(data, BUFFER_TYPES): - data = BYTES_TYPE(data) + data = bytes(data) elif not isinstance(data, bytes): - raise TypeError('data must be bytes, buffer, or memoryview') - _check(_libchromaprint.chromaprint_feed( - self._ctx, data, len(data) // 2 - )) + raise TypeError("data must be bytes, buffer, or memoryview") + _check(_libchromaprint.chromaprint_feed(self._ctx, data, len(data) // 2)) def finish(self): """Finish the fingerprint generation process and retrieve the @@ -157,9 +162,11 @@ """ _check(_libchromaprint.chromaprint_finish(self._ctx)) fingerprint_ptr = ctypes.c_char_p() - _check(_libchromaprint.chromaprint_get_fingerprint( - self._ctx, ctypes.byref(fingerprint_ptr) - )) + _check( + _libchromaprint.chromaprint_get_fingerprint( + self._ctx, ctypes.byref(fingerprint_ptr) + ) + ) fingerprint = fingerprint_ptr.value _libchromaprint.chromaprint_dealloc(fingerprint_ptr) return fingerprint @@ -180,11 +187,17 @@ result_ptr = ctypes.POINTER(ctypes.c_uint32)() result_size = ctypes.c_int() algorithm = ctypes.c_int() - _check(_libchromaprint.chromaprint_decode_fingerprint( - data, len(data), ctypes.byref(result_ptr), ctypes.byref(result_size), - ctypes.byref(algorithm), 1 if base64 else 0 - )) - result = result_ptr[:result_size.value] + _check( + _libchromaprint.chromaprint_decode_fingerprint( + data, + len(data), + ctypes.byref(result_ptr), + ctypes.byref(result_size), + ctypes.byref(algorithm), + 1 if base64 else 0, + ) + ) + result = result_ptr[: result_size.value] _libchromaprint.chromaprint_dealloc(result_ptr) return result, algorithm.value @@ -205,11 +218,17 @@ fp_array[i] = fingerprint[i] result_ptr = ctypes.POINTER(ctypes.c_char)() result_size = ctypes.c_int() - _check(_libchromaprint.chromaprint_encode_fingerprint( - fp_array, len(fingerprint), algorithm, ctypes.byref(result_ptr), - ctypes.byref(result_size), 1 if base64 else 0 - )) - result = result_ptr[:result_size.value] + _check( + _libchromaprint.chromaprint_encode_fingerprint( + fp_array, + len(fingerprint), + algorithm, + ctypes.byref(result_ptr), + ctypes.byref(result_size), + 1 if base64 else 0, + ) + ) + result = result_ptr[: result_size.value] _libchromaprint.chromaprint_dealloc(result_ptr) return result @@ -251,7 +270,9 @@ for i in range(len(fingerprint)): fp_array[i] = fingerprint[i] result_hash = ctypes.c_uint32() - _check(_libchromaprint.chromaprint_hash_fingerprint( - fp_array, len(fingerprint), ctypes.byref(result_hash) - )) + _check( + _libchromaprint.chromaprint_hash_fingerprint( + fp_array, len(fingerprint), ctypes.byref(result_hash) + ) + ) return result_hash.value diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyacoustid-1.3.0/fpcalc.py new/pyacoustid-1.3.1/fpcalc.py --- old/pyacoustid-1.3.0/fpcalc.py 2018-08-22 15:41:03.000000000 +0200 +++ new/pyacoustid-1.3.1/fpcalc.py 1970-01-01 01:00:00.000000000 +0100 @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # This file is part of pyacoustid. # Copyright 2012, Lukas Lalinsky. @@ -17,10 +17,6 @@ """Simple script for calculating audio fingerprints, using the same arguments/output as the fpcalc utility from Chromaprint.""" -from __future__ import division -from __future__ import absolute_import -from __future__ import print_function - import argparse import sys @@ -30,13 +26,19 @@ def main(): parser = argparse.ArgumentParser() - parser.add_argument('-length', metavar='SECS', type=int, default=120, - help='length of the audio data used for fingerprint ' - 'calculation (default 120)') - parser.add_argument('-raw', action='store_true', - help='output the raw uncompressed fingerprint') - parser.add_argument('paths', metavar='FILE', nargs='+', - help='audio file to be fingerprinted') + parser.add_argument( + "-length", + metavar="SECS", + type=int, + default=120, + help="length of the audio data used for fingerprint calculation (default 120)", + ) + parser.add_argument( + "-raw", action="store_true", help="output the raw uncompressed fingerprint" + ) + parser.add_argument( + "paths", metavar="FILE", nargs="+", help="audio file to be fingerprinted" + ) args = parser.parse_args() # make gst not try to parse the args @@ -47,19 +49,25 @@ try: duration, fp = acoustid.fingerprint_file(path, args.length) except Exception: - print("ERROR: unable to calculate fingerprint " - "for file %s, skipping" % path, file=sys.stderr) + print( + f"ERROR: unable to calculate fingerprint for file {path}, skipping", + file=sys.stderr, + ) continue if args.raw: raw_fp = chromaprint.decode_fingerprint(fp)[0] - fp = ','.join(map(str, raw_fp)) + fp = ",".join(map(str, raw_fp)) if not first: - print + print() first = False - print('FILE=%s' % path) - print('DURATION=%d' % duration) - print('FINGERPRINT=%s' % fp.decode('utf8')) + print(f"FILE={path}") + print(f"DURATION={duration}") + if isinstance(fp, bytes): + fp_text = fp.decode("utf8") + else: + fp_text = fp + print(f"FINGERPRINT={fp_text}") -if __name__ == '__main__': +if __name__ == "__main__": main() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyacoustid-1.3.0/pyacoustid.egg-info/PKG-INFO new/pyacoustid-1.3.1/pyacoustid.egg-info/PKG-INFO --- old/pyacoustid-1.3.0/pyacoustid.egg-info/PKG-INFO 2023-09-12 20:00:04.000000000 +0200 +++ new/pyacoustid-1.3.1/pyacoustid.egg-info/PKG-INFO 1970-01-01 01:00:00.000000000 +0100 @@ -1,238 +0,0 @@ -Metadata-Version: 2.1 -Name: pyacoustid -Version: 1.3.0 -Summary: bindings for Chromaprint acoustic fingerprinting and the Acoustid API -Home-page: https://github.com/sampsyo/pyacoustid -Author: Adrian Sampson -Author-email: [email protected] -License: MIT -Platform: ALL -Classifier: Topic :: Multimedia :: Sound/Audio :: Conversion -Classifier: Intended Audience :: Developers -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 3 -License-File: LICENSE - -Chromaprint and Acoustid for Python -=================================== - -`Chromaprint`_ and its associated `Acoustid`_ Web service make up a -high-quality, open-source acoustic fingerprinting system. This package provides -Python bindings for both the fingerprinting algorithm library, which is written -in C but portable, and the Web service, which provides fingerprint lookups. - -.. _Chromaprint: http://acoustid.org/chromaprint -.. _Acoustid: http://acoustid.org/ - - -Installation ------------- - -This library works with Python 2 (2.7+, possibly also 2.6) and Python 3 -(3.3+). - -First, install the `Chromaprint`_ fingerprinting library by `Lukas Lalinsky`__. -(The library itself depends on an FFT library, but it's smart enough to use an -algorithm from software you probably already have installed; see the Chromaprint -page for details.) This module can use either the Chromaprint dynamic library or -the ``fpcalc`` command-line tool, which itself depends on `libavcodec`_. If you -use ``fpcalc``, either ensure that it is on your ``$PATH`` or set the ``FPCALC`` -environment variable to its location. - -__ lukas_ -.. _lukas: https://oxygene.sk/about/ -.. _libavcodec: http://ffmpeg.org/ - -Then you can install this library from `PyPI`_ using `pip`_:: - - $ pip install pyacoustid - -This library uses `audioread`_ to do audio decoding when not using ``fpcalc`` -and `requests`_ to talk to the HTTP API (pip should automatically install -these dependencies). - -.. _pip: http://www.pip-installer.org/ -.. _PyPI: http://pypi.python.org/ -.. _audioread: https://github.com/sampsyo/audioread -.. _requests: http://python-requests.org - - -Running -------- - -You can run the included demonstration script, ``aidmatch.py``, to test your -installation:: - - $ python aidmatch.py mysterious_music.mp3 - -This will show the top metadata match from Acoustid's database. The script uses -`audioread`_ to decode music, so it should transparently use a media library -available on your system (GStreamer, FFmpeg, MAD, or Core Audio). - - -Using in Your Code ------------------- - -The simplest way to use pyacoustid to identify audio files is to call the -``match`` function:: - - >>> import acoustid - >>> for score, recording_id, title, artist in acoustid.match(apikey, path): - >>> ... - -This convenience function uses `audioread`_ to decode audio and parses the -response for you, pulling out the most important track metadata. It returns in -iterable over tuples of relevant information. Everything happens in one fell -swoop. There are also a number of "smaller" functions you can use to perform -parts of the process: - -- ``fingerprint(samplerate, channels, pcmiter)``: Generate a fingerprint for raw - audio data. Specify the audio parameters and give an iterable containing - blocks of PCM data. -- ``fingerprint_file(path)``: Using either the Chromaprint dynamic library or - the ``fpcalc`` command-line tool, fingerprint an audio file. (You can use - ``force_fpcalc`` to use only the latter.) Returns a pair consisting of the - file's duration and its fingerprint. -- ``lookup(apikey, fingerprint, duration)``: Make a request to the `Acoustid`_ - API to look up the fingerprint returned by the previous function. An API key - is required, as is the length, in seconds, of the source audio. Returns a - parsed JSON response. -- ``parse_lookup_result(data)``: Given a parsed JSON response, return an - iterator over tuples containing the match score (a float between 0 and 1), the - MusicBrainz recording ID, title, and artist name for each match. -- ``compare_fingerprints(a, b)``: Compare two fingerprints produced by - `fingerprint_file`, returning a similarity score. - -The module internally performs thread-safe API rate limiting to 3 queries per -second whenever the Web API is called, in accordance with the `Web service -documentation`_. - -If you're running your own Acoustid database server, you can set the base URL -for all API calls with the ``set_base_url`` function. - -Calls to the library can raise ``AcoustidError`` exceptions of two subtypes: -``FingerprintGenerationError`` and ``WebServiceError``. Catch these exceptions -if you want to proceed when audio can't be decoded or no match is found on the -server. ``NoBackendError``, a subclass of ``FingerprintGenerationError``, is -used when the Chromaprint library or fpcalc command-line tool cannot be found. - -.. _Web service documentation: http://acoustid.org/webservice - - -Version History ---------------- - -1.3.0 - Multiple artists are joined by join phrases, as displayed on the web page. - A new (pure-Python) function compares two Chromaprint fingerprints for - similarity. - Search more shared-library locations for the Chromaprint library on Windows. - -1.2.3 - Fix the signedness of numbers returned from - `chromaprint_decode_fingerprint`. - -1.2.2 - Fix a regression in the previous version that caused a `KeyError` crash when - calling `submit`. - -1.2.1 - The `meta` parameter to some API functions can now be a list (instead of - just a single string). - -1.2.0 - Add a `force_fpcalc` option to `fingerprint_file` and `match`. - Avoid leaving a dangling socket after communicating with the server. - Fix a crash when passing a `memoryview` object to the fingerprinter. - API requests can now optionally time out. - More reliably find the library on Windows on Python 3.8. - Add a `hash_fingerprint` function to the low-level library. - -1.1.7 - Include a LICENSE file. - -1.1.6 - In submission, avoid an error on non-integer durations. - A new function, `get_submission_status`, abstracts the API endpoint for - monitoring submissions using the (new) result from the `submit` function. - -1.1.5 - Fix compatibility with Python 3 in the `submit` function. - Errors in `submit` are now also handled correctly (i.e., they raise an - informative `WebServiceError` instead of a `TypeError`). - -1.1.4 - Fix an error on versions of the `fpcalc` tool that report the duration as a - fractional number. - -1.1.3 - Accept `bytearray` objects in addition to other bytes-like types. - -1.1.2 - Fix a possible crash on Unicode text in Python 2 in a non-Unicode locale. - Look for version "1" of the Chromaprint shared library file. - -1.1.1 - Fix a possible setup error on Python 3 (thanks to Simon Chopin). - -1.1.0 - Include ``fpcalc.py`` script in source distributions. - Add Python 3 support (thanks to Igor Tsarev). - -1.0.0 - Include ``fpcalc.py``, a script mimicking the ``fpcalc`` program from the - Chromaprint package. - Handle a ``UnicodeDecodeError`` raised when using the ``fpcalc`` backend on - Windows with Unicode filenames. - Standard error output from ``fpcalc`` is suppressed. - -0.7 - Properly encode Unicode parameters (resolves a ``UnicodeEncodeError`` - in fingerprint submission). - Parse all recordings for each Acoustid lookup result. - -0.6 - Add a new function, ``fingerprint_file``, that automatically selects a - backend for fingerprinting a single file. - -0.5 - Fix response parsing when recording has no artists or title. - Fix compatibility with Python < 2.7. - Add specific ``NoBackendError`` exception. - -0.4 - Fingerprinting can now fall back to using the ``fpcalc`` command-line tool - instead of the Chromaprint dynamic library so the library can be used with - the binary distributions (thanks to Lukas Lalinsky). - Fingerprint submission (thanks to Alastair Porter). - Data chunks can now be buffers as well as bytestrings (fixes compatibility - with pymad). - -0.3 - Configurable API base URL. - Result parser now generates all results instead of returning just one. - Find the chromaprint library on Cygwin. - New module names: ``chromaprint`` and ``acoustid`` (no package). - -0.2 - Compress HTTP requests and responses. - Limit audio decoding to 120 seconds. - Return score from convenience function. - -0.1 - Initial release. - - -Credits -------- - -This library is by Adrian Sampson. Chromaprint and Acoustid are by `Lukas -Lalinsky`__. This package includes the original `ctypes`_-based bindings -written by Lukas. The entire library is made available under the `MIT license`_. -pyacoustid was written to be used with `beets`_, which you should probably check -out. - -__ lukas_ -.. _ctypes: http://docs.python.org/library/ctypes.html -.. _beets: http://beets.radbox.org/ -.. _MIT license: http://www.opensource.org/licenses/mit-license.php diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyacoustid-1.3.0/pyacoustid.egg-info/SOURCES.txt new/pyacoustid-1.3.1/pyacoustid.egg-info/SOURCES.txt --- old/pyacoustid-1.3.0/pyacoustid.egg-info/SOURCES.txt 2023-09-12 20:00:04.000000000 +0200 +++ new/pyacoustid-1.3.1/pyacoustid.egg-info/SOURCES.txt 1970-01-01 01:00:00.000000000 +0100 @@ -1,14 +0,0 @@ -LICENSE -MANIFEST.in -README.rst -acoustid.py -aidmatch.py -chromaprint.py -fpcalc.py -setup.py -pyacoustid.egg-info/PKG-INFO -pyacoustid.egg-info/SOURCES.txt -pyacoustid.egg-info/dependency_links.txt -pyacoustid.egg-info/pbr.json -pyacoustid.egg-info/requires.txt -pyacoustid.egg-info/top_level.txt \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyacoustid-1.3.0/pyacoustid.egg-info/dependency_links.txt new/pyacoustid-1.3.1/pyacoustid.egg-info/dependency_links.txt --- old/pyacoustid-1.3.0/pyacoustid.egg-info/dependency_links.txt 2023-09-12 20:00:04.000000000 +0200 +++ new/pyacoustid-1.3.1/pyacoustid.egg-info/dependency_links.txt 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ - diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyacoustid-1.3.0/pyacoustid.egg-info/pbr.json new/pyacoustid-1.3.1/pyacoustid.egg-info/pbr.json --- old/pyacoustid-1.3.0/pyacoustid.egg-info/pbr.json 2017-04-08 18:23:35.000000000 +0200 +++ new/pyacoustid-1.3.1/pyacoustid.egg-info/pbr.json 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -{"is_release": false, "git_version": "0d56b1d"} \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyacoustid-1.3.0/pyacoustid.egg-info/requires.txt new/pyacoustid-1.3.1/pyacoustid.egg-info/requires.txt --- old/pyacoustid-1.3.0/pyacoustid.egg-info/requires.txt 2023-09-12 20:00:04.000000000 +0200 +++ new/pyacoustid-1.3.1/pyacoustid.egg-info/requires.txt 1970-01-01 01:00:00.000000000 +0100 @@ -1,2 +0,0 @@ -audioread -requests diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyacoustid-1.3.0/pyacoustid.egg-info/top_level.txt new/pyacoustid-1.3.1/pyacoustid.egg-info/top_level.txt --- old/pyacoustid-1.3.0/pyacoustid.egg-info/top_level.txt 2023-09-12 20:00:04.000000000 +0200 +++ new/pyacoustid-1.3.1/pyacoustid.egg-info/top_level.txt 1970-01-01 01:00:00.000000000 +0100 @@ -1,2 +0,0 @@ -acoustid -chromaprint diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyacoustid-1.3.0/pyproject.toml new/pyacoustid-1.3.1/pyproject.toml --- old/pyacoustid-1.3.0/pyproject.toml 1970-01-01 01:00:00.000000000 +0100 +++ new/pyacoustid-1.3.1/pyproject.toml 1970-01-01 01:00:00.000000000 +0100 @@ -0,0 +1,124 @@ +[project] +name = "pyacoustid" +version = "1.3.1" +description = "Bindings for Chromaprint acoustic fingerprinting and the Acoustid API" +authors = [{ name = "Adrian Sampson", email = "[email protected]" }] +readme = "README.rst" +license = "MIT" +requires-python = ">=3.10" +classifiers = [ + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", + "Topic :: Multimedia :: Sound/Audio :: Conversion", +] +dependencies = [ + "audioread", + "requests", +] + +[dependency-groups] +dev = [ + "pytest >= 8.4.2", + "pytest-cov >= 7.0.0", +] +lint = [ + "mypy >= 1.18.2", + "ruff >= 0.6.4", + "types-requests", +] + +[project.urls] +Homepage = "https://github.com/beetbox/pyacoustid" +Repository = "https://github.com/beetbox/pyacoustid" +"Bug Tracker" = "https://github.com/beetbox/pyacoustid/issues" + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" + +[tool.pipx-install] +poethepoet = ">=0.26" +poetry = ">=2.1" + +[tool.poetry] +packages = [ + { include = "acoustid.py" }, + { include = "chromaprint.py" }, +] +include = [ + { path = "aidmatch.py", format = "sdist" }, + { path = "fpcalc.py", format = "sdist" }, +] + +[tool.poe.tasks.check-format] +help = "Check the code for style issues" +cmd = "ruff format --config=pyproject.toml --check --diff" + +[tool.poe.tasks.check-types] +help = "Check the code for typing issues. Accepts mypy options." +cmd = "mypy" + +[tool.poe.tasks.format] +help = "Format the codebase" +cmd = "ruff format --config=pyproject.toml" + +[tool.poe.tasks.lint] +help = "Check the code for linting issues. Accepts ruff options." +cmd = "ruff check --config=pyproject.toml" + +[tool.poe.tasks.test] +help = "Run tests with pytest" +cmd = "pytest $OPTS" +env.OPTS.default = "-p no:cov" + +[tool.poe.tasks.test-with-coverage] +help = "Run tests and record coverage" +ref = "test" +# record coverage for the main packages +# save xml for coverage upload to codecov +# save html report for local dev use +# measure coverage across logical branches +# show which tests cover specific lines in the code (see the HTML report) +env.OPTS = """ +--cov=chromaprint +--cov=acoustid +--cov-report=xml:.reports/coverage.xml +--cov-report=html:.reports/html +--cov-branch +--cov-context=test +""" +[tool.ruff] +target-version = "py310" + +[tool.ruff.lint] +future-annotations = true +select = [ + "E", # pycodestyle + "F", # pyflakes + "G", # flake8-logging-format + "I", # isort + "ISC", # flake8-implicit-str-concat + "N", # pep8-naming + "PT", # flake8-pytest-style + "RUF", # ruff + "UP", # pyupgrade + "TC", # flake8-type-checking + "W", # pycodestyle +] +ignore = [ + "TC006", # no need to quote 'cast's since we use 'from __future__ import annotations' +] + +[tool.ruff.lint.isort] +split-on-trailing-comma = false + +[tool.ruff.lint.flake8-pytest-style] +fixture-parentheses = false +mark-parentheses = false +parametrize-names-type = "csv" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyacoustid-1.3.0/setup.cfg new/pyacoustid-1.3.1/setup.cfg --- old/pyacoustid-1.3.0/setup.cfg 2023-09-12 20:00:04.142952700 +0200 +++ new/pyacoustid-1.3.1/setup.cfg 1970-01-01 01:00:00.000000000 +0100 @@ -1,4 +0,0 @@ -[egg_info] -tag_build = -tag_date = 0 - diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyacoustid-1.3.0/setup.py new/pyacoustid-1.3.1/setup.py --- old/pyacoustid-1.3.0/setup.py 2023-09-12 19:59:29.000000000 +0200 +++ new/pyacoustid-1.3.1/setup.py 1970-01-01 01:00:00.000000000 +0100 @@ -1,57 +0,0 @@ -# This file is part of pyacoustid. -# Copyright 2011, Adrian Sampson. -# -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. - -import os -import sys -from setuptools import setup - - -def _read(fn): - path = os.path.join(os.path.dirname(__file__), fn) - if sys.version_info[0] < 3: - data = open(path).read().decode('utf8') - else: - data = open(path, encoding='utf8').read() - # Special case some Unicode characters; PyPI seems to only like ASCII. - data = data.replace(u'\xe1', u'a') - data = data.replace(u'\u0161', u's') - data = data.replace(u'\xfd', u'y') - return data - - -setup(name='pyacoustid', - version='1.3.0', - description=('bindings for Chromaprint acoustic fingerprinting and the ' - 'Acoustid API'), - author='Adrian Sampson', - author_email='[email protected]', - url='https://github.com/sampsyo/pyacoustid', - license='MIT', - platforms='ALL', - long_description=_read('README.rst'), - - install_requires=['audioread', 'requests'], - - py_modules=[ - 'chromaprint', - 'acoustid', - ], - - classifiers=[ - 'Topic :: Multimedia :: Sound/Audio :: Conversion', - 'Intended Audience :: Developers', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 3', - ], - )
