2727import json
2828import logging
2929import os
30+ import pathlib
3031from typing import TYPE_CHECKING , Any
3132
3233from typing_extensions import Self
@@ -248,29 +249,26 @@ class without a namespace. With the default namespace, reading from a file will
248249 DEFAULT_NAMESPACE = '__DEFAULT__'
249250 DEFAULT_BASE_NAME = "keys"
250251
251- def __init__ (self , namespace , filename = None ):
252- self .namespace = namespace if namespace is not None else self .DEFAULT_NAMESPACE
252+ def __init__ (
253+ self , namespace : str | None = None , filename : str | None = None
254+ ) -> None :
255+ self .namespace = namespace or self .DEFAULT_NAMESPACE
253256
254- if filename is None :
255- # Use a default for the current user
257+ if filename :
258+ self .filename = pathlib .Path (filename ).resolve ()
259+ self .directory_name = self .filename .parent
260+ else :
261+ import platformdirs # Deferred import
256262
257- # Import here because this may not exist on all platforms
258- # pylint: disable=import-outside-toplevel
259- import appdirs
263+ base_dir = platformdirs .user_data_path (self .APP_NAME , self .APP_AUTHOR )
264+ self .directory_name = base_dir / self .KEYS_DIR
260265
261- self .directory_name = os .path .join (
262- appdirs .user_data_dir (self .APP_NAME , self .APP_AUTHOR ), self .KEYS_DIR
263- )
264- base_name = self .DEFAULT_BASE_NAME if namespace is None else self .namespace
265- json_filename = (
266- f'{ base_name } .json' .lower ().replace (':' , '-' ).replace ('/p' , '-p' )
267- )
268- self .filename = os .path .join (self .directory_name , json_filename )
269- else :
270- self .filename = filename
271- self .directory_name = os .path .dirname (os .path .abspath (self .filename ))
266+ base_name = self .namespace if namespace else self .DEFAULT_BASE_NAME
267+ safe_name = base_name .lower ().replace (':' , '-' ).replace ('/' , '-' )
268+
269+ self .filename = self .directory_name / f"{ safe_name } .json"
272270
273- logger .debug (f 'JSON keystore: { self .filename } ' )
271+ logger .debug ('JSON keystore: %s' , self .filename )
274272
275273 @classmethod
276274 def from_device (
@@ -293,7 +291,9 @@ def from_device(
293291
294292 return cls (namespace , filename )
295293
296- async def load (self ):
294+ async def load (
295+ self ,
296+ ) -> tuple [dict [str , dict [str , dict [str , Any ]]], dict [str , dict [str , Any ]]]:
297297 # Try to open the file, without failing. If the file does not exist, it
298298 # will be created upon saving.
299299 try :
@@ -312,17 +312,17 @@ async def load(self):
312312 return next (iter (db .items ()))
313313
314314 # Finally, just create an empty key map for the namespace
315- key_map = {}
315+ key_map : dict [ str , dict [ str , Any ]] = {}
316316 db [self .namespace ] = key_map
317317 return (db , key_map )
318318
319- async def save (self , db ) :
319+ async def save (self , db : dict [ str , dict [ str , dict [ str , Any ]]]) -> None :
320320 # Create the directory if it doesn't exist
321321 if not os .path .exists (self .directory_name ):
322322 os .makedirs (self .directory_name , exist_ok = True )
323323
324324 # Save to a temporary file
325- temp_filename = self .filename + ' .tmp'
325+ temp_filename = self .filename . with_name ( self . filename . name + " .tmp" )
326326 with open (temp_filename , 'w' , encoding = 'utf-8' ) as output :
327327 json .dump (db , output , sort_keys = True , indent = 4 )
328328
@@ -334,16 +334,16 @@ async def delete(self, name: str) -> None:
334334 del key_map [name ]
335335 await self .save (db )
336336
337- async def update (self , name , keys ) :
337+ async def update (self , name : str , keys : PairingKeys ) -> None :
338338 db , key_map = await self .load ()
339339 key_map .setdefault (name , {}).update (keys .to_dict ())
340340 await self .save (db )
341341
342- async def get_all (self ):
342+ async def get_all (self ) -> list [ tuple [ str , PairingKeys ]] :
343343 _ , key_map = await self .load ()
344344 return [(name , PairingKeys .from_dict (keys )) for (name , keys ) in key_map .items ()]
345345
346- async def delete_all (self ):
346+ async def delete_all (self ) -> None :
347347 db , key_map = await self .load ()
348348 key_map .clear ()
349349 await self .save (db )
0 commit comments