diff --git a/music_assistant/controllers/cache.py b/music_assistant/controllers/cache.py index 359f99922..5103e6c6b 100644 --- a/music_assistant/controllers/cache.py +++ b/music_assistant/controllers/cache.py @@ -288,8 +288,7 @@ async def __create_database_indexes(self) -> None: f"ON {DB_TABLE_CACHE}(base_key);" ) await self.database.execute( - f"CREATE INDEX IF NOT EXISTS {DB_TABLE_CACHE}_sub_key_idx " - f"ON {DB_TABLE_CACHE}(sub_key);" + f"CREATE INDEX IF NOT EXISTS {DB_TABLE_CACHE}_sub_key_idx ON {DB_TABLE_CACHE}(sub_key);" ) await self.database.execute( f"CREATE INDEX IF NOT EXISTS {DB_TABLE_CACHE}_category_base_key_idx " diff --git a/music_assistant/controllers/config.py b/music_assistant/controllers/config.py index 6beae0dce..5acbaef83 100644 --- a/music_assistant/controllers/config.py +++ b/music_assistant/controllers/config.py @@ -201,7 +201,7 @@ async def get_provider_config(self, instance_id: str) -> ProviderConfig: if prov.domain == raw_conf["domain"]: break else: - msg = f'Unknown provider domain: {raw_conf["domain"]}' + msg = f"Unknown provider domain: {raw_conf['domain']}" raise KeyError(msg) return ProviderConfig.parse(config_entries, raw_conf) msg = f"No config found for provider id {instance_id}" diff --git a/music_assistant/controllers/media/base.py b/music_assistant/controllers/media/base.py index e3d5291b4..f9b0a5e3e 100644 --- a/music_assistant/controllers/media/base.py +++ b/music_assistant/controllers/media/base.py @@ -735,7 +735,7 @@ async def _get_library_items_by_query( query_parts = [x[5:] if x.lower().startswith("where ") else x for x in query_parts] # concetenate all join and/or where queries if join_parts: - sql_query += f' {" ".join(join_parts)} ' + sql_query += f" {' '.join(join_parts)} " if query_parts: sql_query += " WHERE " + " AND ".join(query_parts) # build final query diff --git a/music_assistant/controllers/music.py b/music_assistant/controllers/music.py index 164f57110..321c8a8c3 100644 --- a/music_assistant/controllers/music.py +++ b/music_assistant/controllers/music.py @@ -1076,7 +1076,7 @@ async def _cleanup_database(self) -> None: self.logger.debug("Performing database cleanup...") # Remove playlog entries older than 90 days await self.database.delete_where_query( - DB_TABLE_PLAYLOG, f"timestamp < strftime('%s','now') - {3600 * 24 * 90}" + DB_TABLE_PLAYLOG, f"timestamp < strftime('%s','now') - {3600 * 24 * 90}" ) # db tables cleanup for ctrl in ( @@ -1509,13 +1509,11 @@ async def __create_database_indexes(self) -> None: ) # index on play_count await self.database.execute( - f"CREATE INDEX IF NOT EXISTS {db_table}_play_count_idx " - f"on {db_table}(play_count);" + f"CREATE INDEX IF NOT EXISTS {db_table}_play_count_idx on {db_table}(play_count);" ) # index on last_played await self.database.execute( - f"CREATE INDEX IF NOT EXISTS {db_table}_last_played_idx " - f"on {db_table}(last_played);" + f"CREATE INDEX IF NOT EXISTS {db_table}_last_played_idx on {db_table}(last_played);" ) # indexes on provider_mappings table diff --git a/music_assistant/controllers/player_queues.py b/music_assistant/controllers/player_queues.py index e4d91a7ef..bfd15c0fd 100644 --- a/music_assistant/controllers/player_queues.py +++ b/music_assistant/controllers/player_queues.py @@ -124,7 +124,7 @@ def __init__(self, *args, **kwargs) -> None: self._prev_states: dict[str, CompareState] = {} self.manifest.name = "Player Queues controller" self.manifest.description = ( - "Music Assistant's core controller " "which manages the queues for all players." + "Music Assistant's core controller which manages the queues for all players." ) self.manifest.icon = "playlist-music" diff --git a/music_assistant/helpers/audio.py b/music_assistant/helpers/audio.py index c21bdbaf7..305b6881e 100644 --- a/music_assistant/helpers/audio.py +++ b/music_assistant/helpers/audio.py @@ -127,8 +127,7 @@ async def crossfade_pcm_parts( return crossfaded_audio # no crossfade_data, return original data instead LOGGER.debug( - "crossfade of pcm chunks failed: not enough data? " - "- fade_in_part: %s - fade_out_part: %s", + "crossfade of pcm chunks failed: not enough data? - fade_in_part: %s - fade_out_part: %s", len(fade_in_part), len(fade_out_part), ) diff --git a/music_assistant/helpers/database.py b/music_assistant/helpers/database.py index 8d1cf2b16..578f666f4 100644 --- a/music_assistant/helpers/database.py +++ b/music_assistant/helpers/database.py @@ -179,10 +179,10 @@ async def insert( """Insert data in given table.""" keys = tuple(values.keys()) if allow_replace: - sql_query = f'INSERT OR REPLACE INTO {table}({",".join(keys)})' + sql_query = f"INSERT OR REPLACE INTO {table}({','.join(keys)})" else: - sql_query = f'INSERT INTO {table}({",".join(keys)})' - sql_query += f' VALUES ({",".join(f":{x}" for x in keys)})' + sql_query = f"INSERT INTO {table}({','.join(keys)})" + sql_query += f" VALUES ({','.join(f':{x}' for x in keys)})" row_id = await self._db.execute_insert(sql_query, values) await self._db.commit() return row_id[0] @@ -199,7 +199,7 @@ async def update( ) -> Mapping: """Update record.""" keys = tuple(values.keys()) - sql_query = f'UPDATE {table} SET {",".join(f"{x}=:{x}" for x in keys)} WHERE ' + sql_query = f"UPDATE {table} SET {','.join(f'{x}=:{x}' for x in keys)} WHERE " sql_query += " AND ".join(f"{x} = :{x}" for x in match) await self.execute(sql_query, {**match, **values}) await self._db.commit() diff --git a/music_assistant/helpers/webserver.py b/music_assistant/helpers/webserver.py index fbdc6e4ee..0478b0d3c 100644 --- a/music_assistant/helpers/webserver.py +++ b/music_assistant/helpers/webserver.py @@ -46,7 +46,7 @@ async def setup( static_content: tuple[str, str, str] | None = None, ) -> None: """Async initialize of module.""" - self._base_url = base_url[:-1] if base_url.endswith("/") else base_url + self._base_url = base_url.removesuffix("/") self._bind_port = bind_port self._static_routes = static_routes self._webapp = web.Application( diff --git a/music_assistant/providers/airplay/provider.py b/music_assistant/providers/airplay/provider.py index d89dbb385..70a035fd0 100644 --- a/music_assistant/providers/airplay/provider.py +++ b/music_assistant/providers/airplay/provider.py @@ -148,7 +148,7 @@ async def handle_async_init(self) -> None: self._players = {} self.cliraop_bin: str | None = await get_cliraop_binary() dacp_port = await select_free_port(39831, 49831) - self.dacp_id = dacp_id = f"{randrange(2 ** 64):X}" + self.dacp_id = dacp_id = f"{randrange(2**64):X}" self.logger.debug("Starting DACP ActiveRemote %s on port %s", dacp_id, dacp_port) self._dacp_server = await asyncio.start_server( self._handle_dacp_request, "0.0.0.0", dacp_port diff --git a/music_assistant/providers/filesystem_smb/__init__.py b/music_assistant/providers/filesystem_smb/__init__.py index 3d2c9cfc1..209a17bc4 100644 --- a/music_assistant/providers/filesystem_smb/__init__.py +++ b/music_assistant/providers/filesystem_smb/__init__.py @@ -170,8 +170,7 @@ async def mount(self) -> None: subfolder = subfolder.replace("\\", "/") if not subfolder.startswith("/"): subfolder = "/" + subfolder - if subfolder.endswith("/"): - subfolder = subfolder[:-1] + subfolder = subfolder.removesuffix("/") env_vars = { **os.environ, diff --git a/music_assistant/providers/hass_players/__init__.py b/music_assistant/providers/hass_players/__init__.py index 056f665ee..c2a321358 100644 --- a/music_assistant/providers/hass_players/__init__.py +++ b/music_assistant/providers/hass_players/__init__.py @@ -170,7 +170,7 @@ async def get_config_entries( player_entities: list[ConfigValueOption] = [] if hass_prov and hass_prov.hass.connected: async for state in _get_hass_media_players(hass_prov): - name = f'{state["attributes"]["friendly_name"]} ({state["entity_id"]})' + name = f"{state['attributes']['friendly_name']} ({state['entity_id']})" player_entities.append(ConfigValueOption(name, state["entity_id"])) return ( ConfigEntry( diff --git a/music_assistant/providers/opensubsonic/__init__.py b/music_assistant/providers/opensubsonic/__init__.py index 197c9c079..2505c386a 100644 --- a/music_assistant/providers/opensubsonic/__init__.py +++ b/music_assistant/providers/opensubsonic/__init__.py @@ -58,7 +58,7 @@ async def get_config_entries( type=ConfigEntryType.STRING, label="Base URL", required=True, - description="Base URL for the server, e.g. " "https://subsonic.mydomain.tld", + description="Base URL for the server, e.g. https://subsonic.mydomain.tld", ), ConfigEntry( key=CONF_PORT, diff --git a/music_assistant/providers/opensubsonic/sonic_provider.py b/music_assistant/providers/opensubsonic/sonic_provider.py index 004c50f8a..22e456658 100644 --- a/music_assistant/providers/opensubsonic/sonic_provider.py +++ b/music_assistant/providers/opensubsonic/sonic_provider.py @@ -118,9 +118,7 @@ async def handle_async_init(self) -> None: raise CredentialError except (AuthError, CredentialError) as e: msg = ( - "Failed to connect to " - f"{self.config.get_value(CONF_BASE_URL)}" - ", check your settings." + f"Failed to connect to {self.config.get_value(CONF_BASE_URL)}, check your settings." ) raise LoginFailed(msg) from e self._enable_podcasts = bool(self.config.get_value(CONF_ENABLE_PODCASTS)) diff --git a/music_assistant/providers/qobuz/__init__.py b/music_assistant/providers/qobuz/__init__.py index 848138bad..c984348f8 100644 --- a/music_assistant/providers/qobuz/__init__.py +++ b/music_assistant/providers/qobuz/__init__.py @@ -498,7 +498,7 @@ def _parse_artist(self, artist_obj: dict): item_id=str(artist_obj["id"]), provider_domain=self.domain, provider_instance=self.instance_id, - url=f'https://open.qobuz.com/artist/{artist_obj["id"]}', + url=f"https://open.qobuz.com/artist/{artist_obj['id']}", ) }, ) @@ -540,7 +540,7 @@ async def _parse_album(self, album_obj: dict, artist_obj: dict | None = None): sample_rate=album_obj["maximum_sampling_rate"] * 1000, bit_depth=album_obj["maximum_bit_depth"], ), - url=f'https://open.qobuz.com/album/{album_obj["id"]}', + url=f"https://open.qobuz.com/album/{album_obj['id']}", ) }, ) @@ -604,7 +604,7 @@ async def _parse_track(self, track_obj: dict) -> Track: sample_rate=track_obj["maximum_sampling_rate"] * 1000, bit_depth=track_obj["maximum_bit_depth"], ), - url=f'https://open.qobuz.com/track/{track_obj["id"]}', + url=f"https://open.qobuz.com/track/{track_obj['id']}", ) }, disc_number=track_obj.get("media_number", 0), @@ -684,7 +684,7 @@ def _parse_playlist(self, playlist_obj): item_id=str(playlist_obj["id"]), provider_domain=self.domain, provider_instance=self.instance_id, - url=f'https://open.qobuz.com/playlist/{playlist_obj["id"]}', + url=f"https://open.qobuz.com/playlist/{playlist_obj['id']}", ) }, is_editable=is_editable, diff --git a/music_assistant/providers/spotify/__init__.py b/music_assistant/providers/spotify/__init__.py index d70167695..fb4711d44 100644 --- a/music_assistant/providers/spotify/__init__.py +++ b/music_assistant/providers/spotify/__init__.py @@ -382,7 +382,7 @@ async def _get_liked_songs_playlist(self) -> Playlist: liked_songs = Playlist( item_id=self._get_liked_songs_playlist_id(), provider=self.lookup_key, - name=f'Liked Songs {self._sp_user["display_name"]}', # TODO to be translated + name=f"Liked Songs {self._sp_user['display_name']}", # TODO to be translated owner=self._sp_user["display_name"], provider_mappings={ ProviderMapping( @@ -529,7 +529,7 @@ async def remove_playlist_tracks( for item in spotify_result["items"]: if not (item and item["track"] and item["track"]["id"]): continue - track_uris.append({"uri": f'spotify:track:{item["track"]["id"]}'}) + track_uris.append({"uri": f"spotify:track:{item['track']['id']}"}) data = {"tracks": track_uris} await self._delete_data(f"playlists/{prov_playlist_id}/tracks", data=data) @@ -906,7 +906,7 @@ async def _get_data(self, endpoint, **kwargs) -> dict[str, Any]: kwargs["country"] = "from_token" if not (auth_info := kwargs.pop("auth_info", None)): auth_info = await self.login() - headers = {"Authorization": f'Bearer {auth_info["access_token"]}'} + headers = {"Authorization": f"Bearer {auth_info['access_token']}"} locale = self.mass.metadata.locale.replace("_", "-") language = locale.split("-")[0] headers["Accept-Language"] = f"{locale}, {language};q=0.9, *;q=0.5" @@ -942,7 +942,7 @@ async def _delete_data(self, endpoint, data=None, **kwargs) -> None: """Delete data from api.""" url = f"https://api.spotify.com/v1/{endpoint}" auth_info = kwargs.pop("auth_info", await self.login()) - headers = {"Authorization": f'Bearer {auth_info["access_token"]}'} + headers = {"Authorization": f"Bearer {auth_info['access_token']}"} async with self.mass.http_session.delete( url, headers=headers, params=kwargs, json=data, ssl=False ) as response: @@ -967,7 +967,7 @@ async def _put_data(self, endpoint, data=None, **kwargs) -> None: """Put data on api.""" url = f"https://api.spotify.com/v1/{endpoint}" auth_info = kwargs.pop("auth_info", await self.login()) - headers = {"Authorization": f'Bearer {auth_info["access_token"]}'} + headers = {"Authorization": f"Bearer {auth_info['access_token']}"} async with self.mass.http_session.put( url, headers=headers, params=kwargs, json=data, ssl=False ) as response: @@ -993,7 +993,7 @@ async def _post_data(self, endpoint, data=None, **kwargs) -> dict[str, Any]: """Post data on api.""" url = f"https://api.spotify.com/v1/{endpoint}" auth_info = kwargs.pop("auth_info", await self.login()) - headers = {"Authorization": f'Bearer {auth_info["access_token"]}'} + headers = {"Authorization": f"Bearer {auth_info['access_token']}"} async with self.mass.http_session.post( url, headers=headers, params=kwargs, json=data, ssl=False ) as response: diff --git a/music_assistant/providers/tunein/__init__.py b/music_assistant/providers/tunein/__init__.py index ea3168e54..d2cab65c1 100644 --- a/music_assistant/providers/tunein/__init__.py +++ b/music_assistant/providers/tunein/__init__.py @@ -179,7 +179,7 @@ def _parse_radio( name=name, provider_mappings={ ProviderMapping( - item_id=f'{details["preset_id"]}--{stream["media_type"]}', + item_id=f"{details['preset_id']}--{stream['media_type']}", provider_domain=self.domain, provider_instance=self.instance_id, audio_format=AudioFormat( diff --git a/pyproject.toml b/pyproject.toml index 2aa638d4f..edb9a5707 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -53,7 +53,7 @@ test = [ "pytest-cov==5.0.0", "syrupy==4.8.1", "tomli==2.2.1", - "ruff==0.8.6", + "ruff==0.9.1", ] [project.scripts] @@ -252,6 +252,7 @@ ignore = [ "PTH202", "ASYNC109", "ASYNC110", + "A005", ] select = ["ALL"] diff --git a/scripts/profiler.py b/scripts/profiler.py index 44d7844bd..c02e91631 100644 --- a/scripts/profiler.py +++ b/scripts/profiler.py @@ -57,7 +57,7 @@ def print_trace(): print( "\n*** Trace for largest memory block - " - f"({largest.count} blocks, {largest.size/1024} Kb) ***" + f"({largest.count} blocks, {largest.size / 1024} Kb) ***" ) for l in largest.traceback.format(): print(l)