Skip to content

Commit

Permalink
Typed cache_handler.CacheFileHandler
Browse files Browse the repository at this point in the history
- Added type annotations to CacheFileHandler

- Updated temporary files
  • Loading branch information
JackDyre committed Aug 9, 2024
1 parent 2cd627c commit 33b5812
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 46 deletions.
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,8 @@ build-backend = "setuptools.build_meta"
dev-dependencies = [
"mypy>=1.11.1",
"pylint>=3.2.6",
"flake8>=7.1.1",
"isort>=5.13.2",
"autopep8>=2.3.1",
]

9 changes: 9 additions & 0 deletions requirements-dev.lock
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,31 @@ astroid==3.2.4
# via pylint
async-timeout==4.0.3
# via redis
autopep8==2.3.1
certifi==2024.7.4
# via requests
charset-normalizer==3.3.2
# via requests
dill==0.3.8
# via pylint
flake8==7.1.1
idna==3.7
# via requests
isort==5.13.2
# via pylint
mccabe==0.7.0
# via flake8
# via pylint
mypy==1.11.1
mypy-extensions==1.0.0
# via mypy
platformdirs==4.2.2
# via pylint
pycodestyle==2.12.1
# via autopep8
# via flake8
pyflakes==3.2.0
# via flake8
pylint==3.2.6
pymemcache==4.0.0
# via spotipy
Expand All @@ -39,6 +47,7 @@ redis==5.0.8
requests==2.32.3
# via spotipy
tomli==2.0.1
# via autopep8
# via mypy
# via pylint
tomlkit==0.13.0
Expand Down
91 changes: 45 additions & 46 deletions spotipy/cache_handler.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
__all__ = [
'CacheHandler',
'CacheFileHandler',
'DjangoSessionCacheHandler',
'FlaskSessionCacheHandler',
'MemoryCacheHandler',
'RedisCacheHandler',
'MemcacheCacheHandler']
"CacheHandler",
"CacheFileHandler",
"DjangoSessionCacheHandler",
"FlaskSessionCacheHandler",
"MemoryCacheHandler",
"RedisCacheHandler",
"MemcacheCacheHandler",
]

import errno
import json
import logging
import os
from abc import ABC, abstractmethod
from .util import CLIENT_CREDS_ENV_VARS
from typing import Dict, Union
from json import JSONEncoder
from pathlib import Path
from typing import Dict, Optional, Type, Union

from redis import RedisError

from .util import CLIENT_CREDS_ENV_VARS

logger = logging.getLogger(__name__)

TokenInfoType = Dict[str, Union[str, int]]
Expand All @@ -33,7 +37,7 @@ class CacheHandler(ABC):
"""

@abstractmethod
def get_cached_token(self) -> TokenInfoType:
def get_cached_token(self) -> Optional[TokenInfoType]:
"""Get and return a token_info dictionary object."""

@abstractmethod
Expand All @@ -42,42 +46,38 @@ def save_token_to_cache(self, token_info: TokenInfoType) -> None:


class CacheFileHandler(CacheHandler):
"""
Handles reading and writing cached Spotify authorization tokens
as json files on disk.
"""

def __init__(self,
cache_path=None,
username=None,
encoder_cls=None):
"""Read and write cached Spotify authorization tokens as json files on disk."""

def __init__(
self,
cache_path: Optional[str] = None,
username: Optional[str] = None,
encoder_cls: Optional[Type[JSONEncoder]] = None,
) -> None:
"""
Parameters:
* cache_path: May be supplied, will otherwise be generated
(takes precedence over `username`)
* username: May be supplied or set as environment variable
(will set `cache_path` to `.cache-{username}`)
* encoder_cls: May be supplied as a means of overwriting the
default serializer used for writing tokens to disk
Initialize CacheFileHandler instance.
:param cache_path: (Optional) Path to cache. (Will override 'username')
:param username: (Optional) Client username. (Can also be supplied via env var.)
:param encoder_cls: (Optional) JSON encoder class to override default.
"""
self.encoder_cls = encoder_cls
if cache_path:
self.cache_path = cache_path
else:
cache_path = ".cache"
username = (username or os.getenv(CLIENT_CREDS_ENV_VARS["client_username"]))
if username:
cache_path += "-" + str(username)
self.cache_path = cache_path

def get_cached_token(self):
token_info = None
username = username or os.getenv(CLIENT_CREDS_ENV_VARS["client_username"])

self.cache_path = (
cache_path
if cache_path is not None
else ".cache" + (f"-{username}" if username is not None else "")
)

def get_cached_token(self) -> Optional[TokenInfoType]:
"""Get cached token from file."""
token_info: Optional[TokenInfoType] = None

try:
f = open(self.cache_path)
token_info_string = f.read()
f.close()
token_info = json.loads(token_info_string)
with Path(self.cache_path).open("r") as f:
token_info = json.load(f)

except OSError as error:
if error.errno == errno.ENOENT:
Expand All @@ -87,14 +87,13 @@ def get_cached_token(self):

return token_info

def save_token_to_cache(self, token_info):
def save_token_to_cache(self, token_info: TokenInfoType) -> None:
"""Save token cache to file."""
try:
f = open(self.cache_path, "w")
f.write(json.dumps(token_info, cls=self.encoder_cls))
f.close()
with Path(self.cache_path).open("w") as f:
json.dump(token_info, f, cls=self.encoder_cls)
except OSError:
logger.warning('Couldn\'t write token to cache at: %s',
self.cache_path)
logger.warning("Couldn't write token to cache at: %s", self.cache_path)


class MemoryCacheHandler(CacheHandler):
Expand Down

0 comments on commit 33b5812

Please sign in to comment.