From f54c78412d8f1b7dded6cd32f3d4e45b731d6767 Mon Sep 17 00:00:00 2001 From: Samuel Coleman Date: Tue, 14 Apr 2026 15:45:23 +0100 Subject: [PATCH 01/10] Replace setup.py with pyproject.toml. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I've specified the “GPL-3.0-or-later” license on the basis that, at the time it was committed, the license URL in `setup.py` linked to [the text of GPL 3.0], and in my experience, “or later” is the typical expectation of forward GPL version compatibility when left unspecified. [the text of GPL 3.0]: https://web.archive.org/web/20110629093753/http://www.gnu.org/copyleft/gpl.html --- README.rst | 79 +++++++++++++++++++++++++++++++++++++--------- itunes/__init__.py | 9 ------ pyproject.toml | 14 ++++++++ setup.py | 21 ------------ 4 files changed, 78 insertions(+), 45 deletions(-) create mode 100644 pyproject.toml delete mode 100644 setup.py diff --git a/README.rst b/README.rst index 1ac9ca0..c45f592 100644 --- a/README.rst +++ b/README.rst @@ -6,26 +6,75 @@ A simple python wrapper to access iTunes Store API http://www.apple.com/itunes/a Installation ------------ -Pypi package available at http://pypi.python.org/pypi/python-itunes/1.0 +The library is distributed `on PyPI`_, +and can be installed into a `virtual environment`_ for your project +with ``pip``: -:: +.. code-block:: sh - $ easy_install python-itunes + $ pip install python-itunes -Or download the code from https://github.com/ocelma/python-itunes/archives/master and then +To install the latest development version, +``pip`` can fetch the source from the Git repository: -:: +.. code-block:: sh - $ python setup.py install + $ pip install git+https://github.com/ocelma/python-itunes -.. note:: +Usually, you would list this dependency in your ``pyproject.toml``: - If you're using python version <= 2.5 you'll need to install simplejson. E.g: +.. code-block:: toml -:: + [project] + # ... + dependencies = [ + "python-itunes", + # or + "python-itunes @ git+https://github.com/ocelma/python-itunes", + ] + +.. _on PyPI: http://pypi.python.org/pypi/python-itunes +.. _virtual environment: https://docs.python.org/3/library/venv.html + +Development +----------- + +To hack on the library itself, +create a venv, +and make an *editable* install of the library: + +.. code-block:: sh + + $ git clone https://github.com/ocelma/python-itunes + $ cd python-itunes + $ python3 -m venv env + $ . env/bin/activate + $ pip install --editable . + +If you get an error like this:: + + ERROR: File "setup.py" or "setup.cfg" not found. Directory cannot be installed in editable mode: /path/to/python-itunes + (A "pyproject.toml" file was found, but editable mode currently requires a setuptools-based build.) - $ easy_install simplejson +...your ``pip`` is too old. +Upgrading the version installed in your venv +will resolve the problem: +.. code-block:: sh + + $ pip install --upgrade pip + +Whenever you open a new terminal, +don't forget to re-activate the venv: + +.. code-block:: sh + + $ cd python-itunes + $ . env/bin/activate + +Then, when you ``import itunes`` in a Python REPL, +changes made to the library source +are available immediately without reinstalling the package. Examples -------- @@ -35,7 +84,7 @@ Search :: import itunes - + # Search band U2 artist = itunes.search_artist('u2')[0] for album in artist.get_albums(): @@ -52,7 +101,7 @@ Search # Global Search 'Beatles' items = itunes.search(query='beatles') - for item in items: + for item in items: print '[' + item.type + ']', item.get_artist(), item.get_name(), item.get_url(), item.get_release_date() # Search 'Angry Birds' game @@ -76,13 +125,13 @@ Lookup # Lookup Achtung Baby album by U2 U2_ACHTUNGBABY_ID = 475390461 album = itunes.lookup(U2_ACHTUNGBABY_ID) - + print album.get_url() print album.get_artwork() - + artist = album.get_artist() tracks = album.get_tracks() - + # Lookup song One from Achtung Baby album by U2 U2_ONE_ID = 475391315 track = itunes.lookup(U2_ONE_ID) diff --git a/itunes/__init__.py b/itunes/__init__.py index 048c6f6..e416622 100644 --- a/itunes/__init__.py +++ b/itunes/__init__.py @@ -14,15 +14,6 @@ except ImportError: from md5 import md5 -__name__ = 'pyitunes' -__doc__ = 'A python interface to search iTunes Store' -__author__ = 'Oscar Celma' -__version__ = '0.2' -__license__ = 'GPL' -__maintainer__ = 'Oscar Celma' -__email__ = 'ocelma@bmat.com' -__status__ = 'Beta' - API_VERSION = '2' # iTunes API version COUNTRY = 'US' # ISO Country Store diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..9e3d283 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,14 @@ +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" + +[project] +name = "python-itunes" +version = "1.0" +description = "A simple python wrapper to access iTunes Store API" +authors = [{ name = "Oscar Celma", email = "ocelma@bmat.com" }] +maintainers = [{ name = "Oscar Celma", email = "ocelma@bmat.com" }] +license = { text = "GPL-3.0-or-later" } + +[project.urls] +source = "https://github.com/ocelma/python-itunes" diff --git a/setup.py b/setup.py deleted file mode 100644 index 0b542e1..0000000 --- a/setup.py +++ /dev/null @@ -1,21 +0,0 @@ -import os.path -try: - from setuptools import setup, Extension -except ImportError: - from distutils.core import setup, Extension - -VERSION = "1.0" - -setup( - name = "python-itunes", - version = VERSION, - description="A simple python wrapper to access iTunes Store API", - author='Oscar Celma', - author_email='ocelma@bmat.com', - maintainer='Oscar Celma', - maintainer_email='ocelma@bmat.com', - license = "http://www.gnu.org/copyleft/gpl.html", - platforms = ["any"], - url="https://github.com/ocelma/python-itunes", - packages=['itunes'], -) From 34fdc14f2d415cc3a3b8eee61ba6aaaeba15f1fa Mon Sep 17 00:00:00 2001 From: Samuel Coleman Date: Tue, 14 Apr 2026 15:45:24 +0100 Subject: [PATCH 02/10] Update iTunes Search API documentation URL. --- README.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index c45f592..13627d1 100644 --- a/README.rst +++ b/README.rst @@ -1,7 +1,9 @@ Python iTunes ============= -A simple python wrapper to access iTunes Store API http://www.apple.com/itunes/affiliates/resources/documentation/itunes-store-web-service-search-api.html +A simple Python wrapper to access `iTunes Search API`_. + +.. _iTunes Search API: https://performance-partners.apple.com/search-api Installation ------------ From e2e3136fbb0217b4ad6393cc0dc355ad6e098b75 Mon Sep 17 00:00:00 2001 From: Samuel Coleman Date: Tue, 14 Apr 2026 15:45:24 +0100 Subject: [PATCH 03/10] Enable syntax highlighting for examples. Co-authored-by: Jag_k <30597878+jag-k@users.noreply.github.com> --- README.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index 13627d1..e6a86e7 100644 --- a/README.rst +++ b/README.rst @@ -83,7 +83,8 @@ Examples Search ~~~~~~ -:: + +.. code-block:: python import itunes @@ -120,7 +121,7 @@ Search Lookup ~~~~~~ -:: +.. code-block:: python import itunes @@ -144,7 +145,7 @@ Lookup Caching JSON results ~~~~~~~~~~~~~~~~~~~~ -:: +.. code-block:: python import itunes @@ -157,6 +158,6 @@ Caching JSON results Tests ----- -:: +.. code-block:: sh $ nosetests tests From 251e76a9a5763d7a1e2e55b17ecba06805fbef41 Mon Sep 17 00:00:00 2001 From: Samuel Coleman Date: Tue, 14 Apr 2026 15:45:24 +0100 Subject: [PATCH 04/10] Replace Py2 urllib2 with Py3 urllib. --- itunes/__init__.py | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/itunes/__init__.py b/itunes/__init__.py index e416622..406a923 100644 --- a/itunes/__init__.py +++ b/itunes/__init__.py @@ -1,18 +1,12 @@ #!/usr/bin/python """A python interface to search iTunes Store""" -import os -import urllib2, urllib -import urlparse -import re import datetime -try: - import simplejson as json -except ImportError: - import json -try: - from hashlib import md5 -except ImportError: - from md5 import md5 +from hashlib import md5 +import json +import numbers +import os +import urllib.parse +import urllib.request API_VERSION = '2' # iTunes API version COUNTRY = 'US' # ISO Country Store @@ -56,23 +50,23 @@ def _download_response(self): data = [] for name in self.params.keys(): value = self.params[name] - if isinstance(value, int) or isinstance(value, float) or isinstance(value, long): + if isinstance(value, numbers.Number): value = str(value) try: - data.append('='.join((name, urllib.quote_plus(value.replace('&', '&').encode('utf8'))))) + data.append('='.join((name, urllib.parse.quote_plus(value.replace('&', '&').encode('utf8'))))) except UnicodeDecodeError: - data.append('='.join((name, urllib.quote_plus(value.replace('&', '&'))))) + data.append('='.join((name, urllib.parse.quote_plus(value.replace('&', '&'))))) data = '&'.join(data) url = HOST_NAME - parsed_url = urlparse.urlparse(url) + parsed_url = urllib.parse.urlsplit(url) if not parsed_url.scheme: url = "http://" + url url += self.method + '?' url += data - request = urllib2.Request(url) - response = urllib2.urlopen(request) + request = urllib.request.Request(url) + response = urllib.request.urlopen(request) return response.read() def execute(self, cacheable=False): @@ -83,8 +77,8 @@ def execute(self, cacheable=False): response = self._download_response() response = clean_json(response) return json.loads(response) - except urllib2.HTTPError, e: - raise self._get_error(e.fp.read()) + except urllib.error.HTTPError as e: + raise self._get_error(e.msg) def _get_cache_key(self): """Cache key""" From 9371542a9ff70b36526122f88219b9a30f897c3a Mon Sep 17 00:00:00 2001 From: Samuel Coleman Date: Tue, 14 Apr 2026 15:45:25 +0100 Subject: [PATCH 05/10] Replace `has_key()` with `in`. Co-authored-by: tal --- itunes/__init__.py | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/itunes/__init__.py b/itunes/__init__.py index 406a923..4ce1cf7 100644 --- a/itunes/__init__.py +++ b/itunes/__init__.py @@ -132,15 +132,15 @@ def _get_params(self): def get(self): self._json_results = self._request(cacheable=is_caching_enabled()) - if self._json_results.has_key('errorMessage'): + if 'errorMessage' in self._json_results: raise ServiceException(type='Error', message=self._json_results['errorMessage']) self._num_results = self._json_results['resultCount'] l = [] for json in self._json_results['results']: type = None - if json.has_key('wrapperType'): + if 'wrapperType' in json: type = json['wrapperType'] - elif json.has_key('kind'): + elif 'kind' in json: type = json['kind'] if type == 'artist': @@ -159,9 +159,9 @@ def get(self): id = json['trackId'] item = Software(id) else: - if json.has_key('collectionId'): + if 'collectionId' in json: id = json['collectionId'] - elif json.has_key('artistId'): + elif 'artistId' in json: id = json['artistId'] item = Item(id) item._set(json) @@ -238,7 +238,7 @@ def __init__(self, id): def _set(self, json): self.json = json #print json - if json.has_key('kind'): + if 'kind' in json: self.type = json['kind'] else: self.type = json['wrapperType'] @@ -254,7 +254,7 @@ def _set_genre(self, json): def _set_release(self, json): self.release_date = None - if json.has_key('releaseDate') and json['releaseDate']: + if 'releaseDate' in json and json['releaseDate']: self.release_date = json['releaseDate'].split('T')[0] def _set_country(self, json): @@ -262,32 +262,32 @@ def _set_country(self, json): def _set_artwork(self, json): self.artwork = dict() - if json.has_key('artworkUrl30'): + if 'artworkUrl30' in json: self.artwork['30'] = json['artworkUrl30'] - if json.has_key('artworkUrl60'): + if 'artworkUrl60' in json: self.artwork['60'] = json['artworkUrl60'] - if json.has_key('artworkUrl100'): + if 'artworkUrl100' in json: self.artwork['100'] = json['artworkUrl100'] - if json.has_key('artworkUrl512'): + if 'artworkUrl512' in json: self.artwork['512'] = json['artworkUrl512'] - if json.has_key('artworkUrl1100'): + if 'artworkUrl1100' in json: self.artwork['1100'] = json['artworkUrl1100'] def _set_url(self, json): self.url = None - if json.has_key('trackViewUrl'): + if 'trackViewUrl' in json: self.url = json['trackViewUrl'] - elif json.has_key('collectionViewUrl'): + elif 'collectionViewUrl' in json: self.url = json['collectionViewUrl'] - elif json.has_key('artistViewUrl'): + elif 'artistViewUrl' in json: self.url = json['artistViewUrl'] # REPR, EQ, NEQ def __repr__(self): if not self.name: - if self.json.has_key('collectionName'): + if 'collectionName' in self.json: self._set_name(self.json['collectionName']) - elif self.json.has_key('artistName'): + elif 'artistName' in self.json: self._set_name(self.json['artistName']) return self.name.encode('utf8') @@ -307,9 +307,9 @@ def _set_name(self, name): # GETTERs def get_id(self): if not self.id: - if self.json.has_key('collectionId'): + if 'collectionId' in self.json: self.id = self.json['collectionId'] - elif self.json.has_key('artistId'): + elif 'artistId' in self.json: self.id = self.json['artistId'] return self.id @@ -451,11 +451,11 @@ def _set(self, json): self.url = json.get('trackViewUrl', None) self.preview_url = json.get('previewUrl', None) self.price = None - if json.has_key('trackPrice') and json['trackPrice'] is not None: + if 'trackPrice' in json and json['trackPrice'] is not None: self.price = round(json['trackPrice'], 4) self.number = json.get('trackNumber', None) self.duration = None - if json.has_key('trackTimeMillis') and json['trackTimeMillis'] is not None: + if 'trackTimeMillis' in json and json['trackTimeMillis'] is not None: self.duration = round(json.get('trackTimeMillis', 0.0)/1000.0, 2) try: self._set_artist(json) @@ -474,7 +474,7 @@ def _set_artist(self, json): self.artist._set(json) def _set_album(self, json): - if json.has_key('collectionId'): + if 'collectionId' in json: id = json['collectionId'] self.album = Album(id) self.album._set(json) @@ -531,7 +531,7 @@ def _set_file_size_bytes(self, json): def _set_current_version_release_date(self, json): self.current_version_release_date = None - if json.has_key('currentVersionReleaseDate') and json['currentVersionReleaseDate']: + if 'currentVersionReleaseDate' in json and json['currentVersionReleaseDate']: self.current_version_release_date = datetime.datetime.strptime( json['currentVersionReleaseDate'], r'%Y-%m-%dT%H:%M:%SZ' ) def _set_bundle_id(self, json): From 797466506a7ae3a03640731507b4f3dd2b6cc051 Mon Sep 17 00:00:00 2001 From: Samuel Coleman Date: Tue, 14 Apr 2026 15:45:25 +0100 Subject: [PATCH 06/10] Fix decoding errors. Co-authored-by: tal --- itunes/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/itunes/__init__.py b/itunes/__init__.py index 4ce1cf7..9878bd5 100644 --- a/itunes/__init__.py +++ b/itunes/__init__.py @@ -67,7 +67,7 @@ def _download_response(self): request = urllib.request.Request(url) response = urllib.request.urlopen(request) - return response.read() + return response.read().decode() def execute(self, cacheable=False): try: @@ -289,7 +289,7 @@ def __repr__(self): self._set_name(self.json['collectionName']) elif 'artistName' in self.json: self._set_name(self.json['artistName']) - return self.name.encode('utf8') + return self.name def __eq__(self, other): if other == None: From f68167ddd68f4a799cea6582e0b4fb74252d77d1 Mon Sep 17 00:00:00 2001 From: Samuel Coleman Date: Tue, 14 Apr 2026 15:45:25 +0100 Subject: [PATCH 07/10] Replace Nose with pytest. --- README.rst | 7 ++++--- pyproject.toml | 7 +++++++ tests/tests.py | 56 +++++++++++++++++++++++++------------------------- 3 files changed, 39 insertions(+), 31 deletions(-) diff --git a/README.rst b/README.rst index e6a86e7..e3c2cc4 100644 --- a/README.rst +++ b/README.rst @@ -43,7 +43,8 @@ Development To hack on the library itself, create a venv, -and make an *editable* install of the library: +and make an *editable* install of the library, +along with development tools: .. code-block:: sh @@ -51,7 +52,7 @@ and make an *editable* install of the library: $ cd python-itunes $ python3 -m venv env $ . env/bin/activate - $ pip install --editable . + $ pip install --editable ".[dev]" If you get an error like this:: @@ -160,4 +161,4 @@ Tests .. code-block:: sh - $ nosetests tests + $ pytest diff --git a/pyproject.toml b/pyproject.toml index 9e3d283..c406d1c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,3 +12,10 @@ license = { text = "GPL-3.0-or-later" } [project.urls] source = "https://github.com/ocelma/python-itunes" + +[project.optional-dependencies] +dev = ["pytest"] + +[tool.pytest] +testpaths = ["tests"] +python_files = ["*.py"] diff --git a/tests/tests.py b/tests/tests.py index d7d58f3..72f5fed 100644 --- a/tests/tests.py +++ b/tests/tests.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -from nose.tools import assert_equal, assert_not_equal, assert_raises, assert_true import itunes +import pytest U2 = 'U2' U2_ONE = 'One' @@ -20,76 +20,76 @@ #SEARCHES def test_search_track_kind(): - assert_equal(itunes.search_track('u2 achtung baby one')[0].get_type(), SONG_KIND) + assert itunes.search_track('u2 achtung baby one')[0].get_type() == SONG_KIND def test_search_album(): - assert_equal(itunes.search_album('u2 achtung baby')[0].get_type(), COLLECTION_KIND) + assert itunes.search_album('u2 achtung baby')[0].get_type() == COLLECTION_KIND def test_search_artist(): - assert_equal(itunes.search_artist('u2')[0].get_id(), U2_ID) + assert itunes.search_artist('u2')[0].get_id() == U2_ID def test_search_artist_store(): U2_URL_ES = 'https://itunes.apple.com/es/artist/u2/id78500?l=en&uo=4' - assert_equal(itunes.search_artist('u2', store='ES')[0].get_id(), U2_ID) - assert_equal(itunes.search_artist('u2', store='ES')[0].get_url(), U2_URL_ES) + assert itunes.search_artist('u2', store='ES')[0].get_id() == U2_ID + assert itunes.search_artist('u2', store='ES')[0].get_url() == U2_URL_ES #LOOKUPS def test_lookup_track(): item = itunes.lookup(U2_ONE_ID) - assert_true(isinstance(item, itunes.Track)) - assert_equal(item.get_id(), U2_ONE_ID) - assert_equal(item.get_name(), U2_ONE) + assert isinstance(item, itunes.Track) + assert item.get_id() == U2_ONE_ID + assert item.get_name() == U2_ONE - assert_equal(item.get_album().get_id(), U2_ACHTUNGBABY_ID) - assert_equal(item.get_artist().get_id(), U2_ID) + assert item.get_album().get_id() == U2_ACHTUNGBABY_ID + assert item.get_artist().get_id() == U2_ID def test_lookup_album(): item = itunes.lookup(U2_ACHTUNGBABY_ID) - assert_true(isinstance(item, itunes.Album)) - assert_equal(item.get_id(), U2_ACHTUNGBABY_ID) - assert_equal(item.get_name(), U2_ACHTUNGBABY) + assert isinstance(item, itunes.Album) + assert item.get_id() == U2_ACHTUNGBABY_ID + assert item.get_name() == U2_ACHTUNGBABY - assert_equal(item.get_artist().get_id(), U2_ID) + assert item.get_artist().get_id() == U2_ID def test_lookup_artist(): item = itunes.lookup(U2_ID) - assert_true(isinstance(item, itunes.Artist)) - assert_equal(item.get_id(), U2_ID) - assert_equal(item.get_name(), U2) + assert isinstance(item, itunes.Artist) + assert item.get_id() == U2_ID + assert item.get_name() == U2 def test_lookup_notfound(): UNKNOWN_ID = 0 - assert_raises(itunes.ServiceException, itunes.lookup, UNKNOWN_ID) + with pytest.raises(itunes.ServiceException): + itunes.lookup(UNKNOWN_ID) #METHODS def test_artist_url(): item = itunes.lookup(U2_ID) - assert_equal(item.get_url(), U2_URL) + assert item.get_url() == U2_URL def test_album_url(): item = itunes.lookup(U2_ACHTUNGBABY_ID) - assert_equal(item.get_url(), U2_ACHTUNGBABY_URL) + assert item.get_url() == U2_ACHTUNGBABY_URL def test_track_url(): item = itunes.lookup(U2_ONE_ID) - assert_equal(item.get_url(), U2_ONE_URL) + assert item.get_url() == U2_ONE_URL def test_album_length(): item = itunes.lookup(U2_ACHTUNGBABY_ID) - assert_true(len(item.get_tracks()) == 26) # 12) + assert len(item.get_tracks()) == 26 # 12) def test_music_video_kind(): item = itunes.lookup(U2_ID) - assert_equal(item.get_music_videos()[0].get_type(), MUSIC_VIDEO_KIND) + assert item.get_music_videos()[0].get_type() == MUSIC_VIDEO_KIND #TEXT: Unicode def test_unicode(): - assert_equal(itunes.search_artist('Björk')[0].get_id(), itunes.search_artist(u'Bj\xf6rk')[0].get_id()) + assert itunes.search_artist('Björk')[0].get_id() == itunes.search_artist(u'Bj\xf6rk')[0].get_id() def test_unicode2(): - assert_equal(itunes.search_artist('Björk')[:5], itunes.search_artist(u'Bj\xf6rk')[:5]) + assert itunes.search_artist('Björk')[:5] == itunes.search_artist(u'Bj\xf6rk')[:5] def test_movie_as_track(): item = itunes.search(query='the godfather', media='movie')[0] - assert_equal(item.get_artist(), None) - + assert item.get_artist() == None From 9c4e165d229e30eecde63a64d486da2016a306ae Mon Sep 17 00:00:00 2001 From: Samuel Coleman Date: Tue, 14 Apr 2026 15:45:26 +0100 Subject: [PATCH 08/10] Remove movie search test. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As of iOS 17.2, movies and TV shows are not listed in the iTunes Store at all. Although the API will still accept queries for the “movie” media type, it does not seem to return any results. --- tests/tests.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/tests.py b/tests/tests.py index 72f5fed..f03ef93 100644 --- a/tests/tests.py +++ b/tests/tests.py @@ -89,7 +89,3 @@ def test_unicode(): def test_unicode2(): assert itunes.search_artist('Björk')[:5] == itunes.search_artist(u'Bj\xf6rk')[:5] - -def test_movie_as_track(): - item = itunes.search(query='the godfather', media='movie')[0] - assert item.get_artist() == None From bd2679b6d2d023d9a37ac9849e5eb98c8e2c6822 Mon Sep 17 00:00:00 2001 From: Samuel Coleman Date: Tue, 14 Apr 2026 15:45:26 +0100 Subject: [PATCH 09/10] Update tested record IDs. --- tests/tests.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/tests.py b/tests/tests.py index f03ef93..19780ad 100644 --- a/tests/tests.py +++ b/tests/tests.py @@ -4,19 +4,19 @@ U2 = 'U2' U2_ONE = 'One' -U2_ACHTUNGBABY = 'Achtung Baby (Deluxe Edition) [Remastered]' # 'Achtung Baby' +U2_ACHTUNGBABY = 'Achtung Baby (20th Anniversary Deluxe Edition)' -MUSIC_VIDEO_KIND = 'music-video' +FEATURE_MOVIE_KIND = 'feature-movie' SONG_KIND = "song" COLLECTION_KIND = "collection" -U2_ONE_ID = 475391315 # Before it was 368617 -U2_ACHTUNGBABY_ID = 475390461 # Before it was 368713 +U2_ONE_ID = 1440809274 +U2_ACHTUNGBABY_ID = 1440808807 U2_ID = 78500 -U2_URL = 'https://itunes.apple.com/us/artist/u2/id%s?uo=4' % U2_ID -U2_ACHTUNGBABY_URL = 'https://itunes.apple.com/us/album/achtung-baby-deluxe-edition/id%s?uo=4' % U2_ACHTUNGBABY_ID -U2_ONE_URL = 'https://itunes.apple.com/us/album/one/id%s?i=%s&uo=4' % (U2_ACHTUNGBABY_ID, U2_ONE_ID) +U2_URL = 'https://music.apple.com/us/artist/u2/%s?uo=4' % U2_ID +U2_ACHTUNGBABY_URL = 'https://music.apple.com/us/album/achtung-baby-20th-anniversary-deluxe-edition/%s?uo=4' % U2_ACHTUNGBABY_ID +U2_ONE_URL = 'https://music.apple.com/us/album/one/%s?i=%s&uo=4' % (U2_ACHTUNGBABY_ID, U2_ONE_ID) #SEARCHES def test_search_track_kind(): @@ -29,7 +29,7 @@ def test_search_artist(): assert itunes.search_artist('u2')[0].get_id() == U2_ID def test_search_artist_store(): - U2_URL_ES = 'https://itunes.apple.com/es/artist/u2/id78500?l=en&uo=4' + U2_URL_ES = 'https://music.apple.com/es/artist/u2/78500?l=en&uo=4' assert itunes.search_artist('u2', store='ES')[0].get_id() == U2_ID assert itunes.search_artist('u2', store='ES')[0].get_url() == U2_URL_ES @@ -81,7 +81,7 @@ def test_album_length(): def test_music_video_kind(): item = itunes.lookup(U2_ID) - assert item.get_music_videos()[0].get_type() == MUSIC_VIDEO_KIND + assert item.get_music_videos()[0].get_type() == FEATURE_MOVIE_KIND #TEXT: Unicode def test_unicode(): From e82c73f51d344a9998983624af93e8cf3d177786 Mon Sep 17 00:00:00 2001 From: Samuel Coleman Date: Tue, 14 Apr 2026 15:45:26 +0100 Subject: [PATCH 10/10] Add GitHub Actions test workflow. --- .github/workflows/test.yaml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .github/workflows/test.yaml diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml new file mode 100644 index 0000000..933df46 --- /dev/null +++ b/.github/workflows/test.yaml @@ -0,0 +1,24 @@ +name: Test +on: + - push + - pull_request +jobs: + test: + name: Run tests + runs-on: ubuntu-latest + steps: + - name: Check out source + uses: actions/checkout@v6 + - name: Restore pip cache + uses: actions/cache@v5 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('**/pyproject.toml') }} + restore-keys: | + ${{ runner.os }}-pip- + - name: Run tests + run: | + python3 -m venv env + . env/bin/activate + pip install --editable ".[dev]" + pytest