From 0868e2f4ba8520c41d071cd5f23b40a985652fe3 Mon Sep 17 00:00:00 2001 From: sigma67 Date: Sat, 5 Oct 2024 11:58:18 +0200 Subject: [PATCH] refactor: use pathlib --- docs/source/conf.py | 3 ++- pyproject.toml | 3 ++- tests/auth/test_oauth.py | 3 +-- ytmusicapi/auth/browser.py | 3 --- ytmusicapi/auth/oauth/token.py | 14 +++++++------- ytmusicapi/mixins/uploads.py | 16 ++++++++-------- ytmusicapi/ytmusic.py | 13 ++++++------- 7 files changed, 26 insertions(+), 29 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 1d7b6152..5dfad5f5 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -12,8 +12,9 @@ # import os import sys +from pathlib import Path -sys.path.insert(0, os.path.abspath(".")) +sys.path.insert(0, Path().resolve().as_posix()) sys.path.insert(0, "../..") from ytmusicapi import __version__ diff --git a/pyproject.toml b/pyproject.toml index 8860d21d..c49596fa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -55,11 +55,12 @@ precision = 2 line-length = 110 [tool.ruff.lint] -ignore = [ "F403", "F405", "F821", "E731" ] +ignore = [ "F403", "F405", "F821", "E731", "PTH123" ] extend-select = [ "I", # isort "UP", # pyupgrade "RUF", # ruff + "PTH", # pathlib ] [tool.mypy] diff --git a/tests/auth/test_oauth.py b/tests/auth/test_oauth.py index 1ecdcf3c..56a752c1 100644 --- a/tests/auth/test_oauth.py +++ b/tests/auth/test_oauth.py @@ -1,5 +1,4 @@ import json -import os import tempfile import time from pathlib import Path @@ -62,7 +61,7 @@ def test_setup_oauth(self, session_mock, json_mock, blank_code, config): assert OAuthToken.is_oauth(oauth_token) oauth_file.close() - os.unlink(oauth_filepath) + Path(oauth_file.name).unlink() def test_oauth_tokens(self, oauth_filepath: str, yt_oauth: YTMusic): # ensure instance initialized token diff --git a/ytmusicapi/auth/browser.py b/ytmusicapi/auth/browser.py index 4187b62c..6094945b 100644 --- a/ytmusicapi/auth/browser.py +++ b/ytmusicapi/auth/browser.py @@ -1,4 +1,3 @@ -import os import platform from typing import Optional @@ -7,8 +6,6 @@ from ytmusicapi.exceptions import YTMusicError, YTMusicUserError from ytmusicapi.helpers import * -path = os.path.dirname(os.path.realpath(__file__)) + os.sep - def is_browser(headers: CaseInsensitiveDict) -> bool: browser_structure = {"authorization", "cookie"} diff --git a/ytmusicapi/auth/oauth/token.py b/ytmusicapi/auth/oauth/token.py index a0071f66..e1596372 100644 --- a/ytmusicapi/auth/oauth/token.py +++ b/ytmusicapi/auth/oauth/token.py @@ -1,8 +1,8 @@ import json -import os import time import webbrowser from dataclasses import dataclass +from pathlib import Path from typing import Optional from requests.structures import CaseInsensitiveDict @@ -68,8 +68,8 @@ def is_expiring(self) -> bool: return self.expires_at - int(time.time()) < 60 @classmethod - def from_json(cls, file_path: str) -> "OAuthToken": - if os.path.isfile(file_path): + def from_json(cls, file_path: Path) -> "OAuthToken": + if file_path.is_file(): with open(file_path) as json_file: file_pack = json.load(json_file) @@ -88,7 +88,7 @@ class RefreshingToken(OAuthToken): credentials: Optional[Credentials] = None #: protected/property attribute enables auto writing token values to new file location via setter - _local_cache: Optional[str] = None + _local_cache: Optional[Path] = None def __getattribute__(self, item): """access token setter to auto-refresh if it is expiring""" @@ -100,11 +100,11 @@ def __getattribute__(self, item): return super().__getattribute__(item) @property - def local_cache(self) -> Optional[str]: + def local_cache(self) -> Optional[Path]: return self._local_cache @local_cache.setter - def local_cache(self, path: str): + def local_cache(self, path: Path): """Update attribute and dump token to new path.""" self._local_cache = path self.store_token() @@ -130,7 +130,7 @@ def prompt_for_token( ref_token = cls(credentials=credentials, **raw_token) ref_token.update(ref_token.as_dict()) if to_file: - ref_token.local_cache = to_file + ref_token.local_cache = Path(to_file) return ref_token def store_token(self, path: Optional[str] = None) -> None: diff --git a/ytmusicapi/mixins/uploads.py b/ytmusicapi/mixins/uploads.py index 2ccdbfd5..a0c6ecb6 100644 --- a/ytmusicapi/mixins/uploads.py +++ b/ytmusicapi/mixins/uploads.py @@ -1,5 +1,4 @@ -import ntpath -import os +from pathlib import Path from typing import Optional, Union import requests @@ -212,11 +211,12 @@ def upload_song(self, filepath: str) -> Union[ResponseStatus, requests.Response] self._check_auth() if not self.auth_type == AuthType.BROWSER: raise YTMusicUserError("Please provide browser authentication before using this function") - if not os.path.isfile(filepath): + fp = Path(filepath) + if not fp.is_file(): raise YTMusicUserError("The provided file does not exist.") supported_filetypes = ["mp3", "m4a", "wma", "flac", "ogg"] - if os.path.splitext(filepath)[1][1:] not in supported_filetypes: + if fp.suffix[1:] not in supported_filetypes: raise YTMusicUserError( "The provided file type is not supported by YouTube Music. Supported file types are " + ", ".join(supported_filetypes) @@ -224,12 +224,12 @@ def upload_song(self, filepath: str) -> Union[ResponseStatus, requests.Response] headers = self.headers.copy() upload_url = f"https://upload.youtube.com/upload/usermusic/http?authuser={headers['x-goog-authuser']}" - filesize = os.path.getsize(filepath) + filesize = fp.stat().st_size if filesize >= 314572800: # 300MB in bytes - msg = f"File {filepath} has size {filesize} bytes, which is larger than the limit of 300MB" + msg = f"File {fp} has size {filesize} bytes, which is larger than the limit of 300MB" raise YTMusicUserError(msg) - body = ("filename=" + ntpath.basename(filepath)).encode("utf-8") + body = ("filename=" + fp.name).encode("utf-8") headers.pop("content-encoding", None) headers["content-type"] = "application/x-www-form-urlencoded;charset=utf-8" headers["X-Goog-Upload-Command"] = "start" @@ -239,7 +239,7 @@ def upload_song(self, filepath: str) -> Union[ResponseStatus, requests.Response] headers["X-Goog-Upload-Command"] = "upload, finalize" headers["X-Goog-Upload-Offset"] = "0" upload_url = response.headers["X-Goog-Upload-URL"] - with open(filepath, "rb") as file: + with open(fp, "rb") as file: response = requests.post(upload_url, data=file, headers=headers, proxies=self.proxies) if response.status_code == 200: diff --git a/ytmusicapi/ytmusic.py b/ytmusicapi/ytmusic.py index 199d04a8..2cccae95 100644 --- a/ytmusicapi/ytmusic.py +++ b/ytmusicapi/ytmusic.py @@ -1,10 +1,10 @@ import gettext import json import locale -import os import time from contextlib import suppress from functools import partial +from pathlib import Path from typing import Optional, Union import requests @@ -121,12 +121,11 @@ def __init__( self.oauth_credentials = ( oauth_credentials if oauth_credentials is not None else OAuthCredentials() ) - auth_filepath: Optional[str] = None + auth_path: Optional[Path] = None if isinstance(self.auth, str): auth_str: str = self.auth - if os.path.isfile(auth_str): - with open(auth_str) as json_file: - auth_filepath = auth_str + if (auth_path := Path(auth_str)).is_file(): + with open(auth_path) as json_file: input_json = json.load(json_file) else: input_json = json.loads(auth_str) @@ -137,7 +136,7 @@ def __init__( if OAuthToken.is_oauth(self._input_dict): self._token = RefreshingToken( - credentials=self.oauth_credentials, _local_cache=auth_filepath, **self._input_dict + credentials=self.oauth_credentials, _local_cache=auth_path, **self._input_dict ) self.auth_type = AuthType.OAUTH_CUSTOM_CLIENT if oauth_credentials else AuthType.OAUTH_DEFAULT @@ -161,7 +160,7 @@ def __init__( with suppress(locale.Error): locale.setlocale(locale.LC_ALL, "en_US.UTF-8") - locale_dir = os.path.abspath(os.path.dirname(__file__)) + os.sep + "locales" + locale_dir = Path(__file__).parent.resolve() / "locales" self.lang = gettext.translation("base", localedir=locale_dir, languages=[language]) self.parser = Parser(self.lang)