Fix misc. pylint errors

This commit is contained in:
nathom 2021-04-10 16:05:31 -07:00
parent 820735e602
commit de1db82da8
5 changed files with 68 additions and 39 deletions

View file

@ -1 +1,4 @@
'''streamrip: the all in one music downloader.
'''
__version__ = "0.4" __version__ = "0.4"

View file

@ -1,3 +1,5 @@
'''A config class that manages arguments between the config file and CLI.'''
import copy import copy
import logging import logging
import os import os
@ -99,21 +101,27 @@ class Config:
self._path = path self._path = path
if not os.path.isfile(self._path): if not os.path.isfile(self._path):
logger.debug(f"Creating yaml config file at '{self._path}'") logger.debug("Creating yaml config file at '%s'", self._path)
self.dump(self.defaults) self.dump(self.defaults)
else: else:
self.load() self.load()
def save(self): def save(self):
"""Save the config state to file."""
self.dump(self.file) self.dump(self.file)
def reset(self): def reset(self):
"""Reset the config file."""
if not os.path.isdir(CONFIG_DIR): if not os.path.isdir(CONFIG_DIR):
os.makedirs(CONFIG_DIR, exist_ok=True) os.makedirs(CONFIG_DIR, exist_ok=True)
self.dump(self.defaults) self.dump(self.defaults)
def load(self): def load(self):
"""Load infomation from the config files, making a deepcopy."""
with open(self._path) as cfg: with open(self._path) as cfg:
for k, v in yaml.load(cfg).items(): for k, v in yaml.load(cfg).items():
self.file[k] = v self.file[k] = v
@ -125,27 +133,18 @@ class Config:
logger.debug("Config loaded") logger.debug("Config loaded")
self.__loaded = True self.__loaded = True
def update_from_cli(self, **kwargs):
for category in (self.downloads, self.metadata, self.filters):
for key in category.keys():
if kwargs.get(key) is None:
continue
# For debugging's sake
og_value = category[key]
new_value = kwargs[key] or og_value
category[key] = new_value
if og_value != new_value:
logger.debug("Updated %s config key from args: %s", key, new_value)
def dump(self, info): def dump(self, info):
"""Given a state of the config, save it to the file.
:param info:
"""
with open(self._path, "w") as cfg: with open(self._path, "w") as cfg:
logger.debug("Config saved: %s", self._path) logger.debug("Config saved: %s", self._path)
yaml.dump(info, cfg) yaml.dump(info, cfg)
@property @property
def tidal_creds(self): def tidal_creds(self):
"""Return a TidalClient compatible dict of credentials."""
creds = dict(self.file["tidal"]) creds = dict(self.file["tidal"])
logger.debug(creds) logger.debug(creds)
del creds["quality"] # should not be included in creds del creds["quality"] # should not be included in creds
@ -153,6 +152,7 @@ class Config:
@property @property
def qobuz_creds(self): def qobuz_creds(self):
"""Return a QobuzClient compatible dict of credentials."""
return { return {
"email": self.file["qobuz"]["email"], "email": self.file["qobuz"]["email"],
"pwd": self.file["qobuz"]["password"], "pwd": self.file["qobuz"]["password"],
@ -161,14 +161,19 @@ class Config:
} }
def creds(self, source: str): def creds(self, source: str):
"""Return a Client compatible dict of credentials.
:param source:
:type source: str
"""
if source == "qobuz": if source == "qobuz":
return self.qobuz_creds return self.qobuz_creds
elif source == "tidal": if source == "tidal":
return self.tidal_creds return self.tidal_creds
elif source == "deezer": if source == "deezer":
return dict() return dict()
else:
raise InvalidSourceError(source) raise InvalidSourceError(source)
def __getitem__(self, key): def __getitem__(self, key):
assert key in ("file", "defaults", "session") assert key in ("file", "defaults", "session")

View file

@ -1,3 +1,7 @@
'''A simple wrapper over an sqlite database that stores
the downloaded media IDs.
'''
import logging import logging
import os import os
import sqlite3 import sqlite3
@ -37,7 +41,7 @@ class MusicDB:
:type item_id: str :type item_id: str
:rtype: bool :rtype: bool
""" """
logger.debug(f"Checking database for ID {item_id}") logger.debug("Checking database for ID %s", item_id)
with sqlite3.connect(self.path) as conn: with sqlite3.connect(self.path) as conn:
return ( return (
conn.execute( conn.execute(
@ -52,7 +56,7 @@ class MusicDB:
:param item_id: :param item_id:
:type item_id: str :type item_id: str
""" """
logger.debug(f"Adding ID {item_id}") logger.debug("Adding ID %s", item_id)
with sqlite3.connect(self.path) as conn: with sqlite3.connect(self.path) as conn:
try: try:
conn.execute( conn.execute(
@ -60,6 +64,6 @@ class MusicDB:
(item_id,), (item_id,),
) )
conn.commit() conn.commit()
except sqlite3.Error as e: except sqlite3.Error as err:
if "UNIQUE" not in str(e): if "UNIQUE" not in str(err):
raise raise

View file

@ -1,3 +1,7 @@
'''These classes parse information from Clients into a universal,
downloadable form.
'''
import logging import logging
import os import os
import re import re
@ -90,6 +94,7 @@ class Track:
:param kwargs: id, filepath_format, meta, quality, folder :param kwargs: id, filepath_format, meta, quality, folder
""" """
self.client = client self.client = client
self.id = None
self.__dict__.update(kwargs) self.__dict__.update(kwargs)
# adjustments after blind attribute sets # adjustments after blind attribute sets
@ -116,7 +121,7 @@ class Track:
def load_meta(self): def load_meta(self):
"""Send a request to the client to get metadata for this Track.""" """Send a request to the client to get metadata for this Track."""
assert hasattr(self, "id"), "id must be set before loading metadata" assert self.id is not None, "id must be set before loading metadata"
self.resp = self.client.get(self.id, media_type="track") self.resp = self.client.get(self.id, media_type="track")
self.meta = TrackMetadata( self.meta = TrackMetadata(
@ -143,7 +148,7 @@ class Track:
def _get_tracklist(resp, source): def _get_tracklist(resp, source):
if source == "qobuz": if source == "qobuz":
return resp["tracks"]["items"] return resp["tracks"]["items"]
elif source in ("tidal", "deezer"): if source in ("tidal", "deezer"):
return resp["tracks"] return resp["tracks"]
raise NotImplementedError(source) raise NotImplementedError(source)
@ -228,7 +233,7 @@ class Track:
try: try:
tqdm_download(dl_info, temp_file) # downloads file tqdm_download(dl_info, temp_file) # downloads file
except NonStreamable: except NonStreamable:
logger.debug(f"Track is not downloadable {dl_info}") logger.debug("Track is not downloadable %s", dl_info)
click.secho("Track is not available for download", fg="red") click.secho("Track is not available for download", fg="red")
return False return False
@ -569,6 +574,7 @@ class Tracklist(list):
>>> tlist[2] >>> tlist[2]
IndexError IndexError
""" """
essence_regex = re.compile(r"([^\(]+)(?:\s*[\(\[][^\)][\)\]])*")
def get(self, key: Union[str, int], default=None): def get(self, key: Union[str, int], default=None):
if isinstance(key, str): if isinstance(key, str):
@ -681,8 +687,7 @@ class Tracklist(list):
Used to group two albums that may be named similarly, but not exactly Used to group two albums that may be named similarly, but not exactly
the same. the same.
""" """
# fixme: compile this first match = Tracklist.essence_regex.match(album)
match = re.match(r"([^\(]+)(?:\s*[\(\[][^\)][\)\]])*", album)
if match: if match:
return match.group(1).strip().lower() return match.group(1).strip().lower()

View file

@ -1,3 +1,5 @@
'''Manages the information that will be embeded in the audio file. '''
import json import json
import logging import logging
import re import re
@ -55,6 +57,7 @@ class TrackMetadata:
:param album: album dict from API :param album: album dict from API
:type album: Optional[dict] :type album: Optional[dict]
""" """
self.title = None
self.album = None self.album = None
self.albumartist = None self.albumartist = None
self.composer = None self.composer = None
@ -201,7 +204,7 @@ class TrackMetadata:
self.title = f"{work}: {self.title}" self.title = f"{work}: {self.title}"
@property @property
def artist(self) -> Union[str, None]: def artist(self) -> Optional[str]:
"""Returns the value to set for the artist tag. Defaults to """Returns the value to set for the artist tag. Defaults to
`self.albumartist` if there is no track artist. `self.albumartist` if there is no track artist.
@ -213,6 +216,8 @@ class TrackMetadata:
if self._artist is not None: if self._artist is not None:
return self._artist return self._artist
return None
@artist.setter @artist.setter
def artist(self, val: str): def artist(self, val: str):
"""Sets the internal artist variable to val. """Sets the internal artist variable to val.
@ -237,8 +242,13 @@ class TrackMetadata:
if isinstance(self._genres, list): if isinstance(self._genres, list):
genres = re.findall(r"([^\u2192\/]+)", "/".join(self._genres)) genres = re.findall(r"([^\u2192\/]+)", "/".join(self._genres))
no_repeats = [] no_repeats = []
[no_repeats.append(g) for g in genres if g not in no_repeats]
for genre in genres:
if genre not in no_repeats:
no_repeats.append(genre)
return ", ".join(no_repeats) return ", ".join(no_repeats)
elif isinstance(self._genres, str): elif isinstance(self._genres, str):
return self._genres return self._genres
@ -264,9 +274,9 @@ class TrackMetadata:
if hasattr(self, "_copyright"): if hasattr(self, "_copyright"):
if self._copyright is None: if self._copyright is None:
return None return None
cr = re.sub(r"(?i)\(P\)", PHON_COPYRIGHT, self._copyright) copyright = re.sub(r"(?i)\(P\)", PHON_COPYRIGHT, self._copyright)
cr = re.sub(r"(?i)\(C\)", COPYRIGHT, cr) copyright = re.sub(r"(?i)\(C\)", COPYRIGHT, copyright)
return cr return copyright
logger.debug("Accessed copyright tag before setting, return None") logger.debug("Accessed copyright tag before setting, return None")
return None return None
@ -282,7 +292,7 @@ class TrackMetadata:
self._copyright = val self._copyright = val
@property @property
def year(self) -> Union[str, None]: def year(self) -> Optional[str]:
"""Returns the year published of the track. """Returns the year published of the track.
:rtype: str :rtype: str
@ -294,6 +304,8 @@ class TrackMetadata:
if self.date is not None: if self.date is not None:
return self.date[:4] return self.date[:4]
return None
@year.setter @year.setter
def year(self, val): def year(self, val):
"""Sets the internal year variable to val. """Sets the internal year variable to val.
@ -334,12 +346,12 @@ class TrackMetadata:
container = container.lower() container = container.lower()
if container in ("flac", "vorbis"): if container in ("flac", "vorbis"):
return self.__gen_flac_tags() return self.__gen_flac_tags()
elif container in ("mp3", "id3"): if container in ("mp3", "id3"):
return self.__gen_mp3_tags() return self.__gen_mp3_tags()
elif container in ("alac", "m4a", "mp4", "aac"): if container in ("alac", "m4a", "mp4", "aac"):
return self.__gen_mp4_tags() return self.__gen_mp4_tags()
else:
raise InvalidContainerError(f"Invalid container {container}") raise InvalidContainerError(f"Invalid container {container}")
def __gen_flac_tags(self) -> Tuple[str, str]: def __gen_flac_tags(self) -> Tuple[str, str]:
"""Generate key, value pairs to tag FLAC files. """Generate key, value pairs to tag FLAC files.
@ -349,7 +361,7 @@ class TrackMetadata:
for k, v in FLAC_KEY.items(): for k, v in FLAC_KEY.items():
tag = getattr(self, k) tag = getattr(self, k)
if tag: if tag:
logger.debug(f"Adding tag {v}: {repr(tag)}") logger.debug("Adding tag %s: %s", v, tag)
yield (v, str(tag)) yield (v, str(tag))
def __gen_mp3_tags(self) -> Tuple[str, str]: def __gen_mp3_tags(self) -> Tuple[str, str]: